<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>qutebrowser development blog</title><link href="https://blog.qutebrowser.org/" rel="alternate"></link><link href="https://blog.qutebrowser.org/feeds/all.atom.xml" rel="self"></link><id>https://blog.qutebrowser.org/</id><updated>2022-12-14T21:19:56+01:00</updated><entry><title>Happy 9th birthday, qutebrowser!</title><link href="https://blog.qutebrowser.org/happy-9th-birthday-qutebrowser.html" rel="alternate"></link><published>2022-12-14T21:19:56+01:00</published><updated>2022-12-14T21:19:56+01:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2022-12-14:/happy-9th-birthday-qutebrowser.html</id><summary type="html">&lt;p&gt;qutebrowser is turning 9 today! I’ll use the opportunity for a – perhaps
slightly tl;dr – overview of how it all came to be. As you might notice
by the length of this post, stopping to write once I started writing
something like this… isn’t exactly my forte! Hopefully …&lt;/p&gt;</summary><content type="html">&lt;p&gt;qutebrowser is turning 9 today! I’ll use the opportunity for a – perhaps
slightly tl;dr – overview of how it all came to be. As you might notice
by the length of this post, stopping to write once I started writing
something like this… isn’t exactly my forte! Hopefully the wall of text
will be interesting nevertheless :).&lt;/p&gt;
&lt;div class="section" id="the-death-of-dwb"&gt;
&lt;h2&gt;The death of dwb&lt;/h2&gt;
&lt;p&gt;Back in 2013, I was a happy user of
&lt;a class="reference external" href="https://wiki.archlinux.org/index.php?title=Dwb&amp;amp;oldid=709191"&gt;dwb&lt;/a&gt;,
but it became apparent that the project would die at some point. It was
clear that dwb would need to make the &lt;a class="reference external" href="https://trac.webkit.org/wiki/WebKit2"&gt;switch to
WebKit2&lt;/a&gt;, but the author
(portix) didn’t have the bandwidth to do so – as far as I remember, they
said it’d basically be a full rewrite, and it’s not going to happen.&lt;/p&gt;
&lt;p&gt;While dwb &lt;a class="reference external" href="https://bitbucket.org/portix/dwb/commits/all"&gt;lived on for another 3 years or
so&lt;/a&gt;, many dwb users –
including me – were looking for alternatives. There were things like
&lt;a class="reference external" href="https://www.uzbl.org/"&gt;uzbl&lt;/a&gt; or
&lt;a class="reference external" href="https://luakit.github.io/"&gt;luakit&lt;/a&gt;, and addons like
&lt;a class="reference external" href="http://vimperator.org/"&gt;Vimperator&lt;/a&gt;, but for some reason or another,
those just didn’t fit the bill.&lt;/p&gt;
&lt;p&gt;Back then, WebKit – especially WebKit 1, still used by most of those
projects – was plagued by frequent hangs and crashes (and it being a
single-process model, a renderer crash meant that your whole browser did
go down with it).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="a-new-browser-on-the-horizon"&gt;
&lt;h2&gt;A new browser on the horizon&lt;/h2&gt;
&lt;p&gt;I toyed with the idea of taking over dwb maintenance – however, it was a
C/GTK codebase. While I was writing microcontroller firmware for a
living in C for a couple of years, it always seemed an odd choice to me
for more OOP-like GUI programming. With projects like
&lt;a class="reference external" href="https://blog.wireshark.org/2013/10/switching-to-qt/"&gt;Wireshark&lt;/a&gt; or
&lt;a class="reference external" href="https://web.archive.org/web/20160905185309/https://wiki.lxde.org/en/Migrate_from_GTK+_to_Qt"&gt;LXDE&lt;/a&gt;
wanting to switch to Qt at the time, it also became clear that GTK
wasn’t what I wanted things to be based on. The only real alternative to
build a web browser was Qt
(&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Electron_(software_framework)"&gt;Electron&lt;/a&gt;
was only 5 months old!).&lt;/p&gt;
&lt;p&gt;With plans about a new Chromium-based QtWebEngine &lt;a class="reference external" href="https://www.qt.io/blog/2013/09/12/introducing-the-qt-webengine"&gt;already on the
horizon&lt;/a&gt;,
this seemed like a great choice. In terms of programming language, the
choice was between Python and C++. C++ is the “native” Qt language, and
Python bindings &lt;a class="reference external" href="https://en.wikipedia.org/wiki/PyQt"&gt;have been
around&lt;/a&gt; since 1998 (!) and were
maintained very well. Anything else was out of the question pretty much.
Since I had some more Python knowledge than C++ knowledge, and C++ is…
quite a beast, I decided to go with Python.&lt;/p&gt;
&lt;p&gt;And thus, with thoughts along the lines of “eh, there are good libraries
for it, how hard can it be?”, exactly 9 years ago today, &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/11a94957dc038fc27c5ff976197ad2b2d0352d20"&gt;I started
qutebrowser&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It initially was focused on dwb “refugees”, and much of that is still
visible today: The &lt;a class="reference external" href="https://d4.alternativeto.net/UabccB8j6-yRr4no66Rm_0ubcl3B-EmkzXMGnTEu73I/rs:fit:1200:1200:0/g:ce:0:0/YWJzOi8vZGlzdC9zL2Y1NmU1Yjg2LWZhYTYtZTExMS05NDU2LTAwMjU5MDJjN2U3M18yX2Z1bGwucG5n.jpg"&gt;look of the
UI&lt;/a&gt;,
almost all keybindings, the split between book- and quickmarks (probably
a &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/882"&gt;bad idea&lt;/a&gt;),
the idea of having external userscripts (probably a &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/6063"&gt;bad
name&lt;/a&gt;), etc.
etc. In other areas, qutebrowser most likely had a pioneering role: As
far as I know, it was the first vim-like browser to introduce a more
shell-like command interface, with things like &lt;tt class="docutils literal"&gt;:open &lt;span class="pre"&gt;-t&lt;/span&gt;&lt;/tt&gt; or
&lt;tt class="docutils literal"&gt;:open &lt;span class="pre"&gt;-w&lt;/span&gt;&lt;/tt&gt; rather than separate &lt;tt class="docutils literal"&gt;:open&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;:winopen&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;:tabopen&lt;/tt&gt; commands. Others like
&lt;a class="reference external" href="https://github.com/tridactyl/tridactyl"&gt;Tridactyl&lt;/a&gt; later followed
suit.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="towards-the-first-release-and-then-some-more"&gt;
&lt;h2&gt;Towards the first release, and then some more&lt;/h2&gt;
&lt;p&gt;It took a lot of work until, exactly a year later, &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/releases/tag/v0.1"&gt;v0.1 was finally
released&lt;/a&gt;.
Later, &lt;a class="reference external" href="http://vimperator.org/"&gt;Vimperator&lt;/a&gt; died with &lt;a class="reference external" href="https://blog.mozilla.org/addons/2015/08/21/the-future-of-developing-firefox-add-ons/"&gt;Firefox
dropping XUL
extensions&lt;/a&gt;,
and between 2014 and 2019 or so, &lt;a class="reference external" href="https://pkgstats.archlinux.de/packages/qutebrowser"&gt;more and more
people&lt;/a&gt; switched
to qutebrowser (up to around 10% of all Archlinux users participating in
package statistics).&lt;/p&gt;
&lt;p&gt;More recently, I was able to work on qutebrowser during my study summer
break &lt;a class="reference external" href="https://www.indiegogo.com/projects/qutebrowser-a-keyboard-focused-vim-like-browser#/"&gt;in
2016&lt;/a&gt;,
again &lt;a class="reference external" href="https://www.kickstarter.com/projects/the-compiler/qutebrowser-v10-with-per-domain-settings/"&gt;in
2018&lt;/a&gt;,
and finally for a longer time as a part-time job &lt;a class="reference external" href="https://github.com/sponsors/The-Compiler"&gt;since
2019&lt;/a&gt;. I’m humbled by all
the support, it’s what still keeps me going – it’s fair to say that I
probably would have burned out and/or stopped by now if I was employed
100% still. Turns out, after all, a web browser isn’t exactly an easy
thing to do as your first big open source project. Big kudos to all the
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser#similar-projects"&gt;other
projects&lt;/a&gt;
which have been going for years if not decades: It’s not easy, and the
occasional entitled user who’s pushy or angry at you for their favourite
feature™ &lt;em&gt;still&lt;/em&gt; not being implemented certainly does not help.
Thankfully, those cases are rare: All in all, I’m thankful for the
qutebrowser community being so understanding, patient and helpful! &amp;lt;3&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="another-big-transition"&gt;
&lt;h2&gt;Another big transition&lt;/h2&gt;
&lt;p&gt;It’s probably fair to say that dwb died during the transition from
WebKit 1 to 2. Such major upgrades – while often reasonable and needed –
tend to use a lot of energy and effort.&lt;/p&gt;
&lt;p&gt;In 2016, qutebrowser had its own first big migration, when QtWebEngine
finally was ready enough to add support for it. Nowadays, QtWebKit is
still supported, though mostly for historical reasons. Chances are big
it will be &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/4039"&gt;all
gone&lt;/a&gt; for the
v3.0.0 release.&lt;/p&gt;
&lt;p&gt;Nowadays, qutebrowser is in a somewhat similar big transition again: It
desperately needs to migrate to Qt 6 to keep things up to date, but –
while not quite a rewrite – doing so is a bunch of work. With
qutebrowser getting older, more popular, and also getting lots and lots
more contributions (often in slighly chaotic ways, &lt;a class="reference external" href="https://press.stripe.com/working-in-public"&gt;as things go with
open source&lt;/a&gt;), this
transition is probably the most challenging of them all yet! There are
many more things to take into consideration than there have been six
years ago. Still, much of it has &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/5395"&gt;been going
on&lt;/a&gt; ever
since Qt 6.2 with QtWebEngine was released in September 2021, with &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/tree/qt6-v2"&gt;a
branch with almost 300
commits&lt;/a&gt;
being nearly finished. If you haven’t yet, you should probably &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/7202"&gt;give it
a try&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="looking-forward-towards-qutebrowser-v3"&gt;
&lt;h2&gt;Looking forward towards qutebrowser v3&lt;/h2&gt;
&lt;p&gt;There are still some challenges to overcome on the development side of
things, and some &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/milestones/v3.0.0"&gt;other stuff I’d like to at least look
at&lt;/a&gt; for
the v3.0.0 release. Last year, my job situation changed as well: Instead
of being employed 40% over the entire year (often taking a lot more
energy and mind-space than those 40%), I’m now busy teaching between
September and February. On the flip-side of the coin, that means I don’t
have anything other than open source (qutebrowser, pytest, and the
occasional paid pytest company training) to worry about between March
and August. Last year has shown that this works out much better,
especially for big chunks of work like this.&lt;/p&gt;
&lt;p&gt;Even though things are still very busy dayjob-wise now (and will be
until March), I’m hoping we can still work on some of the remaining Qt 6
blockers, and then I’m hoping to still be able to finish v3.0 early next
year. Thanks also to everyone who keeps the ball rolling while I might
be busy with other stuff for a while – especially
&lt;a class="reference external" href="https://github.com/toofar"&gt;&amp;#64;toofar&lt;/a&gt;, who has been doing amazing and
steady work over the last couple of years!&lt;/p&gt;
&lt;p&gt;Onwards, and already looking forward to qutebrowser being a decade old
in late 2023!&lt;/p&gt;
&lt;/div&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>Better nightly builds on CI, state of Qt 6 support, and steps towards v3</title><link href="https://blog.qutebrowser.org/better-nightly-builds-on-ci-state-of-qt-6-support-and-steps-towards-v3.html" rel="alternate"></link><published>2022-06-22T15:17:28+02:00</published><updated>2022-06-22T15:24:25+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2022-06-22:/better-nightly-builds-on-ci-state-of-qt-6-support-and-steps-towards-v3.html</id><summary type="html">&lt;p&gt;Today I've worked on improving the nightly build support on CI, and nightly builds are now finally available as individual files instead of being zipped into one big one.&lt;/p&gt;
&lt;p&gt;This means it's now easier for people on macOS and Windows to test the latest changes before they are released, by …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Today I've worked on improving the nightly build support on CI, and nightly builds are now finally available as individual files instead of being zipped into one big one.&lt;/p&gt;
&lt;p&gt;This means it's now easier for people on macOS and Windows to test the latest changes before they are released, by simply going to the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/actions/workflows/nightly.yml"&gt;latest nightly build&lt;/a&gt; and grabbing a macOS/Windows build under &amp;quot;Artifacts&amp;quot;.&lt;/p&gt;
&lt;p&gt;This now also includes builds of the qt6-v2 branch, and I'd really welcome having some more testers there! qutebrowser developers (and some brave[*] users) have been using it as daily driver since a while, and it's generally regarded to be ready to use. If you are on Linux, there's mkvenv.py support, Flatpak builds and an Archlinux AUR package available too, see &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/7202"&gt;the issue for all the details&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Please give it a spin and open a new issue if you run into any trouble!&lt;/p&gt;
&lt;p&gt;There still is a lot of work to do to actually integrate this into the master branch and getting qutebrowser v3.0.0 out, but most of the remaining work is stuff behind the scenes now - from an user's perspective, the qt6-v2 branch should be pretty much ready.&lt;/p&gt;
&lt;p&gt;For the next few weeks, my plan is to get back to merging some PRs, and regularily rebase the qt6-v2 branch on master to get them in there as well. I'll also start teaching Python at the university again in September (until February), so the clock is ticking a bit... I'm hoping that I'll still be able to work on qutebrowser and get this all wrapped up on the side though (only teaching two days a week, plus preparation/admin stuff).&lt;/p&gt;
&lt;p&gt;[*] The English word, not the browser ;)&lt;/p&gt;
</content></entry><entry><title>CVE-2021-41146: Arbitrary command execution in qutebrowser on Windows via URL handler</title><link href="https://blog.qutebrowser.org/cve-2021-41146-arbitrary-command-execution-in-qutebrowser-on-windows-via-url-handler.html" rel="alternate"></link><published>2021-10-21T19:28:57+02:00</published><updated>2021-10-21T19:28:57+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2021-10-21:/cve-2021-41146-arbitrary-command-execution-in-qutebrowser-on-windows-via-url-handler.html</id><summary type="html">&lt;p&gt;I'm happy to announce that I just released qutebrowser v2.4.0!&lt;/p&gt;
&lt;p&gt;This release fixes a high-severity arbitrary command execution on Windows via
URL handlers, see the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/security/advisories/GHSA-vw27-fwjf-5qxm"&gt;security advisory&lt;/a&gt;
and &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/8f46ba3f6dc7b18375f7aa63c48a1fe461190430"&gt;commit message&lt;/a&gt;
for details.&lt;/p&gt;
&lt;p&gt;Windows users are urged to update as soon as possible. For everyone
else, this is a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I'm happy to announce that I just released qutebrowser v2.4.0!&lt;/p&gt;
&lt;p&gt;This release fixes a high-severity arbitrary command execution on Windows via
URL handlers, see the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/security/advisories/GHSA-vw27-fwjf-5qxm"&gt;security advisory&lt;/a&gt;
and &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/8f46ba3f6dc7b18375f7aa63c48a1fe461190430"&gt;commit message&lt;/a&gt;
for details.&lt;/p&gt;
&lt;p&gt;Windows users are urged to update as soon as possible. For everyone
else, this is a rather quiet release, with the most interesting
improvement perhaps being slightly improved Greasemonkey support.&lt;/p&gt;
&lt;p&gt;The full changelog is available on the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/releases/tag/v2.4.0"&gt;release page&lt;/a&gt;,
also see the &lt;a class="reference external" href="https://www.reddit.com/r/qutebrowser/comments/qcwsbd/v240_released_critical_rce_fix_on_windows/"&gt;Reddit post&lt;/a&gt;
for discussion.&lt;/p&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>qutebrowser moving to Libera Chat</title><link href="https://blog.qutebrowser.org/qutebrowser-moving-to-libera-chat.html" rel="alternate"></link><published>2021-05-26T10:52:52+02:00</published><updated>2021-05-26T10:52:52+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2021-05-26:/qutebrowser-moving-to-libera-chat.html</id><summary type="html">&lt;p&gt;This blog has been lying dormant for almost a year now, but rest assured it's
still alive. I usually don't bother posting minor release announcements here
(they can be found on the &lt;a class="reference external" href="https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser-announce"&gt;announcement mailinglist&lt;/a&gt; as
well as the &lt;a class="reference external" href="https://www.reddit.com/r/qutebrowser/"&gt;subreddit&lt;/a&gt;),
on top of that I totally forgot writing a blog post …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This blog has been lying dormant for almost a year now, but rest assured it's
still alive. I usually don't bother posting minor release announcements here
(they can be found on the &lt;a class="reference external" href="https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser-announce"&gt;announcement mailinglist&lt;/a&gt; as
well as the &lt;a class="reference external" href="https://www.reddit.com/r/qutebrowser/"&gt;subreddit&lt;/a&gt;),
on top of that I totally forgot writing a blog post about the v2.0.0 release...&lt;/p&gt;
&lt;p&gt;With that out of the way, I want to announce that qutebrowser, like many other
projects, has moved its IRC chat from Freenode to
&lt;a class="reference external" href="https://libera.chat"&gt;Libera Chat&lt;/a&gt;, after a rather hostile and sudden
&lt;a class="reference external" href="https://gist.github.com/joepie91/df80d8d36cd9d1bde46ba018af497409"&gt;takeover of Freenode&lt;/a&gt;
by &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Andrew_Lee_(entrepreneur)"&gt;Andrew Lee&lt;/a&gt; / &lt;tt class="docutils literal"&gt;rasengan&lt;/tt&gt;
(founder of the VPN provider Private Internet Access, and apparently
&lt;a class="reference external" href="https://www.scmp.com/week-asia/people/article/2175439/no-k-drama-fresh-prince-south-korea-real-royalty-and-hes-american"&gt;crown prince of South Korea&lt;/a&gt;,
or something).&lt;/p&gt;
&lt;p&gt;I spent literally more than half my life on Freenode:&lt;/p&gt;
&lt;blockquote&gt;
-- NickServ: Information on The-Compiler (account The-Compiler):
-- NickServ: Registered : Dec 30 02:21:14 2006 (14y 21w 4d ago)&lt;/blockquote&gt;
&lt;p&gt;and thus was quite surprised when a (now former) Freenode staffer I trust
messaged me two weeks ago. He asked me what I'd do in the hypothetical case
Freenode was being taken over, and I wasn't sure what to think. It all sounded
very far away, and I was hoping it wouldn't turn out that way.&lt;/p&gt;
&lt;p&gt;A week later, unfortunately, the &lt;a class="reference external" href="https://twitter.com/freenodestaff/status/1395046345145307140"&gt;takeover happened&lt;/a&gt;. All the draft
resignation letters suddenly weren't drafts anymore, with the Freenode staff
quitting. The staff started to a new network &lt;a class="reference external" href="https://libera.chat"&gt;Libera Chat&lt;/a&gt;, and
at that point, I joined  the #qutebrowser channels there to make sure they
weren't taken over. Thankfully, another community member (&lt;a class="reference external" href="http://arza.us/"&gt;arza&lt;/a&gt;) had already taken care of that, all that was left for me is
to officially register the qutebrowser project there. Despite Libera &lt;a class="reference external" href="https://libera.chat/news/one-week-of-libera-chat"&gt;being run over&lt;/a&gt; by new users, project
registrations and other user requests, the registration went through quickly and
smoothly. There were a couple of initial server hiccups, but it was clear those people
knew how to run a community. The same can't be said about the new Freenode
admins, unfortunately...&lt;/p&gt;
&lt;p&gt;I didn't move yet, as I still wanted to see how this whole thing pans out. In
case people wanted to move before the channel did, I made sure to point out
&amp;quot;#qutebrowser on libera.chat exists&amp;quot; in the channel topic on Freenode.&lt;/p&gt;
&lt;p&gt;I was planning to do the full move tomorrow. While Andrew Lee and the new
Freenode admins &lt;a class="reference external" href="https://freenode.net/news/for-foss"&gt;continue to claim&lt;/a&gt; that
they're doing the right thing for FOSS, their behavior speaks for itself: After
&lt;a class="reference external" href="https://www.devever.net/~hl/freenode_abuse"&gt;taking over a single channel&lt;/a&gt;,
then retroactively &lt;a class="reference external" href="https://github.com/freenode/web-7.0/pull/513/files"&gt;adjusting their policy&lt;/a&gt; accordingly, tonight this
happened:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;05:02 -&amp;gt; freenodecom (&lt;a class="reference external" href="mailto:~com&amp;#64;freenode/staff"&gt;~com&amp;#64;freenode/staff&lt;/a&gt;) has joined #qutebrowser&lt;/p&gt;
&lt;p&gt;05:02 -- freenodecom has changed topic for #qutebrowser from &amp;quot;Current: v2.2.2 - #qutebrowser on irc.libera.chat exists, full move ~soon - [...]&amp;quot; to &amp;quot;This channel has moved to ##qutebrowser. The topic is in violation of freenode policy: &lt;a class="reference external" href="https://freenode.net/policies"&gt;https://freenode.net/policies&lt;/a&gt;&amp;quot;&lt;/p&gt;
&lt;p&gt;05:02 &amp;lt;&amp;#64;freenodecom&amp;gt; This channel has been reopened with respect to the communities and new users. The topic is in violation of freenode policy: &lt;a class="reference external" href="https://freenode.net/policies"&gt;https://freenode.net/policies&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;05:02 &amp;lt;&amp;#64;freenodecom&amp;gt; The new channel is ##qutebrowser&lt;/p&gt;
&lt;p&gt;05:02 &amp;lt;- freenodecom (&lt;a class="reference external" href="mailto:~com&amp;#64;freenode/staff"&gt;~com&amp;#64;freenode/staff&lt;/a&gt;) has left #qutebrowser&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The same thing happened to many other channels, including e.g. the &lt;a class="reference external" href="https://twitter.com/fosdem/status/1397454352835653632"&gt;channel for
the FOSDEM conference&lt;/a&gt;,
the third-largest channel on Freenode.&lt;/p&gt;
&lt;p&gt;Of course, after the backlash they claim this was by mistake:&lt;/p&gt;
&lt;blockquote&gt;
06:15 -- rasengan (&lt;a class="reference external" href="mailto:~rasengan&amp;#64;freenode/staff/rasengan"&gt;~rasengan&amp;#64;freenode/staff/rasengan&lt;/a&gt;): [Global Notice] In the recent policy enforcement, some channels were erroneously included. We greatly apologize for the inconvenience. Please contact us in #freenode-services or &lt;a class="reference external" href="mailto:contact-us&amp;#64;freenode.net"&gt;contact-us&amp;#64;freenode.net&lt;/a&gt;. Thanks for your patience and choosing freenode!&lt;/blockquote&gt;
&lt;p&gt;My take on this: It &lt;strong&gt;really doesn't matter&lt;/strong&gt; whether some additional channels
were included by mistake. Automatically closing channels (after being active
communities for years!) based on some kind of match on the topic mentioning
Libera Chat is malicious power abuse no matter how you twist it. Not only that,
it's grossly incompetent on top of that.&lt;/p&gt;
&lt;p&gt;I originally planned to set up something like &lt;a class="reference external" href="https://github.com/42wim/matterbridge"&gt;Matterbridge&lt;/a&gt; to bridge the
Freenode and Libera channels, so that people can move over at their own pace.
With the
#qutebrowser channel now forcibly removed by Freenode out of the blue, I'm not
going to bother reinstantiating it. Effective immediately, the IRC chat for
qutebrowser has &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/7961cf73553847ea265a388b736fffac77dae66a"&gt;moved&lt;/a&gt;
to &lt;a class="reference external" href="ircs://irc.libera.chat:6697/#qutebrowser"&gt;irc.libera.chat&lt;/a&gt;, with a
&lt;a class="reference external" href="https://kiwiirc.com/nextclient/irc.libera.chat:+6697/#qutebrowser"&gt;webchat&lt;/a&gt;
by KiwiIRC.&lt;/p&gt;
&lt;p&gt;I urge other projects to do the same sooner rather than later. From what it
looks like, Freenode can't be salvaged, and it's probably only going to get
worse.&lt;/p&gt;
&lt;p&gt;I'm also planning to play with &lt;a class="reference external" href="https://github.com/42wim/matterbridge"&gt;Matterbridge&lt;/a&gt; regardless, and see if I can maybe
bridge the IRC channel to more modern platforms like &lt;a class="reference external" href="https://matrix.org/"&gt;Matrix&lt;/a&gt;, &lt;a class="reference external" href="https://discord.com/"&gt;Discord&lt;/a&gt; or a &lt;a class="reference external" href="https://telegram.org/"&gt;Telegram&lt;/a&gt; groupchat.  It'd be an interesting experiment to see
if that'd attract more/different people than an (arguably somewhat dated) IRC
channel. But let's take things one step at a time.&lt;/p&gt;
&lt;p&gt;The sudden loss of a community I joined when I was 13 years old is saddening,
and it's crazy how quickly this all went downhill. Let's move on, to Libera
Chat!&lt;/p&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>Paying it forward</title><link href="https://blog.qutebrowser.org/paying-it-forward.html" rel="alternate"></link><published>2020-06-12T12:02:48+02:00</published><updated>2020-06-12T12:02:48+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2020-06-12:/paying-it-forward.html</id><summary type="html">&lt;p&gt;As mentioned in my &lt;a class="reference external" href="https://blog.qutebrowser.org/paving-the-road-towards-qutebrowser-v20.html"&gt;last post&lt;/a&gt;, I'm earning what's basically a small part-time
income from qutebrowser donations - thanks again to everyone who's donating
money, it means a lot!&lt;/p&gt;
&lt;p&gt;To pay it forward, I decided to donate to some of the projects qutebrowser is
relying on:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;3$ per month (indefinitely) to …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;As mentioned in my &lt;a class="reference external" href="https://blog.qutebrowser.org/paving-the-road-towards-qutebrowser-v20.html"&gt;last post&lt;/a&gt;, I'm earning what's basically a small part-time
income from qutebrowser donations - thanks again to everyone who's donating
money, it means a lot!&lt;/p&gt;
&lt;p&gt;To pay it forward, I decided to donate to some of the projects qutebrowser is
relying on:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;3$ per month (indefinitely) to &lt;a class="reference external" href="https://github.com/sponsors/nedbat"&gt;Ned Batchelder&lt;/a&gt; of &lt;a class="reference external" href="https://github.com/nedbat/coveragepy"&gt;coverage.py&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;1$ per month (indefinitely) to the &lt;a class="reference external" href="https://github.com/sponsors/Homebrew"&gt;Homebrew&lt;/a&gt; package manager for macOS&lt;/li&gt;
&lt;li&gt;50$ to &lt;a class="reference external" href="https://palletsprojects.com/donate"&gt;Pallets&lt;/a&gt;, the organization behind Flask and Jinja2&lt;/li&gt;
&lt;li&gt;50$ to the &lt;a class="reference external" href="https://www.python.org/psf/donations/"&gt;Python Software Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;42€ to &lt;a class="reference external" href="https://github.com/htgoebel"&gt;Hartmut Goebel&lt;/a&gt; of &lt;a class="reference external" href="http://www.pyinstaller.org/funding.html"&gt;PyInstaller&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;15€ to &lt;a class="reference external" href="https://ko-fi.com/mgedmin"&gt;mgedmin&lt;/a&gt; of &lt;a class="reference external" href="https://github.com/mgedmin/check-manifest"&gt;check-manifest&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your own project relies on libraries taking donations and you can afford to
do so, I'd encourage you to do the same! It doesn't have to be a lot: As I've
experienced with qutebrowser, a lot of small donations can make a big
difference.&lt;/p&gt;
</content></entry><entry><title>Paving the road towards qutebrowser v2.0</title><link href="https://blog.qutebrowser.org/paving-the-road-towards-qutebrowser-v20.html" rel="alternate"></link><published>2020-04-30T22:15:46+02:00</published><updated>2020-05-04T12:14:50+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2020-04-30:/paving-the-road-towards-qutebrowser-v20.html</id><summary type="html">&lt;p&gt;Today, it's been exactly 6 months since I launched the
&lt;a class="reference external" href="https://github.com/sponsors/The-Compiler"&gt;GitHub Sponsors campaign&lt;/a&gt; - time flies!&lt;/p&gt;
&lt;p&gt;I wanted to use this opportunity to update everyone on what has been going on,
on my plans for qutebrowser's future, and on various other bits and bytes - I
have a lot of things I …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Today, it's been exactly 6 months since I launched the
&lt;a class="reference external" href="https://github.com/sponsors/The-Compiler"&gt;GitHub Sponsors campaign&lt;/a&gt; - time flies!&lt;/p&gt;
&lt;p&gt;I wanted to use this opportunity to update everyone on what has been going on,
on my plans for qutebrowser's future, and on various other bits and bytes - I
have a lot of things I want to write down in my head, so this might get rather
long. Grab some beverage of your choice, and feel free to skip over sections
which don't seem relevant for you!&lt;/p&gt;
&lt;p&gt;In case you're reading this via the Python or Qt Planet and need some context:
&lt;a class="reference external" href="https://www.qutebrowser.org"&gt;qutebrowser&lt;/a&gt; is a web browser with vim-like keybindings, based on Python and Qt.&lt;/p&gt;
&lt;div class="section" id="founding-a-company"&gt;
&lt;h2&gt;Founding a company&lt;/h2&gt;
&lt;p&gt;(Note that the donation amounts mentioned here are rounded figures. Thus, they
should still be roughly accurate if you substitute USD by CHF or EUR.)&lt;/p&gt;
&lt;p&gt;After starting the crowdfunding, I had no idea what to expect. If I had to
guess, I'd probably have expected a couple hundred USD per month. I'm happy to
report that I'm getting an average of around 1000 USD in donations since
November.&lt;/p&gt;
&lt;p&gt;I'm very happy to receive so many donations - this is &lt;a class="reference external" href="https://reference.kemitchell.com/top-donations-developers.html"&gt;quite extraordinary&lt;/a&gt; for
a somewhat niche open source project, and I'm grateful to have an awesome
community around qutebrowser! However, getting regular donations also meant a
lot of additional &amp;quot;bureaucracy&amp;quot; work. I had to fill out US tax-exemption forms
(W8-BEN) for GitHub, and I had to found my own small company to take care of
things like taxation or social security contributions for the income.&lt;/p&gt;
&lt;p&gt;Founding a small freelancing company is something I wanted to do anyways: I did
some small freelancing gigs during my studies, and that's something I wanted to
continue building upon.&lt;/p&gt;
&lt;a class="reference external image-reference" href="https://bruhin.software/"&gt;&lt;img alt="Bruhin Software Logo" src="/images/bruhinsw.png" /&gt;&lt;/a&gt;
&lt;p&gt;Thus, &lt;a class="reference external" href="https://bruhin.software/"&gt;Bruhin Software&lt;/a&gt; was born. In case you're wondering: The bear paw is
based on the family &lt;a class="reference external" href="https://www.chgh.ch/1800-b/bracher-brysacher/bruhin.html"&gt;coat of arms&lt;/a&gt; for my last name &amp;quot;Bruhin&amp;quot;, which needed to
be part of the company name due to Swiss laws for sole proprietorship companies.&lt;/p&gt;
&lt;p&gt;Getting everything set up took some time: To combat employments by
a single company disguised as self-employment, you typically have to start
working as a company and prove that you have at least three different customers,
as well as things like a logo or business cards.&lt;/p&gt;
&lt;p&gt;Thankfully, I already had some ideas lined up during my studies, so I could do
various gigs in late 2019 and early 2020:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;I was in Berlin in November - besides &lt;a class="reference external" href="https://www.youtube.com/watch?v=zdsBS5BXGqQ"&gt;speaking at&lt;/a&gt; the Qt World Summit and
finally meeting the people behind Qt at the Qt Contributors Summit, I also
gave a training about advanced Python and pytest at a company.&lt;/li&gt;
&lt;li&gt;Around January/February/March, I updated a &lt;a class="reference external" href="https://studentenportal.ch/"&gt;website&lt;/a&gt; run by an
&lt;a class="reference external" href="https://www.openhsr.ch/"&gt;Open Source student association&lt;/a&gt; (both links in German). That website is a
platform for students to upload cheatsheets and other documents. I modernized
it from an outdated tech stack (Django 1.8 which was supported until April
2018, Python 2, server with &lt;a class="reference external" href="https://twitter.com/the_compiler/status/1239831837272309760"&gt;2000 days&lt;/a&gt; uptime and broken RAID) to something
current and maintainable again.&lt;/li&gt;
&lt;li&gt;In February, I was in Dresden (Germany) for another Python/pytest training.&lt;/li&gt;
&lt;li&gt;I gave a training on pytest basics in London in March.&lt;/li&gt;
&lt;li&gt;In April, I gave a remote training on writing GUIs using &lt;a class="reference external" href="https://wiki.qt.io/Qt_for_Python"&gt;Qt for Python&lt;/a&gt;
(PySide2).&lt;/li&gt;
&lt;/ul&gt;
&lt;a class="reference external image-reference" href="https://www.youtube.com/watch?v=zdsBS5BXGqQ"&gt;&lt;img alt="Me speaking at Qt World Summit" src="/images/qtws.png" /&gt;&lt;/a&gt;
&lt;p&gt;I don't intend this to get something too big - and I'm not financially dependent
on either donations or freelancing work, as I'm still employed 40% by a
university. Still: If you're interested in trainings or consulting around Python
(especially the language itself, testing with pytest, or writing GUIs with PyQt5
or PySide2): Please reach out to &lt;a class="reference external" href="&amp;lt;mailto:florian&amp;#64;bruhin.software&amp;gt;"&gt;florian&amp;#64;bruhin.software&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Back to bureaucracy: After failing to figure out how to best handle the
rather unique situation around donations and such, I reached out to a &lt;a class="reference external" href="https://www.stt.ch/"&gt;tax
professional&lt;/a&gt; (website in German) in February. That was a great idea: I'm happy
to report that yesterday, I finally got the official confirmation that I'm
(part-time) self-employed.&lt;/p&gt;
&lt;p&gt;In the meantime, I also took care of some other things, like making sure my
accounting (something I had ignored so far) was up-to-date. Again, I intend to
get some professional help where needed, but I think it's good to have some
overview over things personally as well.&lt;/p&gt;
&lt;p&gt;Long story short: Setting things up was a rather long but exciting journey. With
that out of the way, I can now get back to doing more for qutebrowser again.&lt;/p&gt;
&lt;p&gt;Doing some other work for a while definitely was a good variation, though it can
be difficult to juggle three responsibilities (employment at the university,
freelancing, qutebrowser) at times.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="funding-campaign"&gt;
&lt;h2&gt;Funding campaign&lt;/h2&gt;
&lt;p&gt;Back to the GitHub Sponsors funding: Originally, I wanted to order shirts,
stickers and swag in May. This won't be happening for now, as I don't trust
postal services in various countries to be reliable at the moment (and even if
they are: they are overloaded enough right now).&lt;/p&gt;
&lt;p&gt;Thus, the shipping date for those physical rewards is currently postponed
indefinitely. I'll send out updates via GitHub Sponsors as soon as there's some
news on that front.&lt;/p&gt;
&lt;img alt="A qutebrowser shirt" src="/images/shirts.jpg" /&gt;
&lt;p&gt;Thanks to all your generous donations, I reached GitHub's $5000 matching cap
around March. GitHub Sponsors still remains an excellent platform for collecting
funding, as they have no fees, not even for currency conversions. I still have
some ideas for alternative funding options via Stripe, but that's not a priority
for me right now.&lt;/p&gt;
&lt;p&gt;From time to time, people ask me how much money I'm still missing in donations.
I struggle to find an answer for that question: Working on qutebrowser isn't
primarily about money, otherwise I wouldn't still be doing it after 6.5 years.
Even if you ignore the &amp;quot;historical&amp;quot; work and pick the lowest rate I'm willing to
work for as a freelancer (50 USD/h which I've billed for some open-source work
before, for non-commercial projects I really like): The 1000 USD would lead to
around 20h of work per month. I think it's safe to say that I'm doing more than
that on average, especially if you consider community reach-out, which is still
something I find very important. As an example: Just today, I replied to one
private mail related to qutebrowser, answered to a new issue, three mailinglist
mails, a couple of Reddit posts, and some questions in IRC. I like hearing from
all the people using qutebrowser (and helping them), though!&lt;/p&gt;
&lt;p&gt;With the bureaucracy out of the way and no planned freelancing gigs right now,
at this point I can commit to doing a bit more work on qutebrowser. To start
with, I plan to work on qutebrowser exclusively for a day per week (in addition
to the small day-to-day things). It's possible I'll be able to ramp
that up soon - for the next 4-5 weeks, there's still a lot to finish for
university lectures.&lt;/p&gt;
&lt;p&gt;Around June/July/August, I might also be able to devote some bigger blocks of time
to qutebrowser as there are no weekly university preparation deadlines - for
example, I could work for a week or two on qutebrowser only, and then on
university stuff for another week or two. I will need to experiment a bit to see
what works best.&lt;/p&gt;
&lt;p&gt;Like probably a lot of people, I'm currently stuck working from my home-office,
which is my 11m² bedroom. Productivity-wise, that probably isn't optimal, but
we'll see how things go. So far, I seem to manage quite well, though I'm looking
forward to going to the office for university work again some time in the
(hopefully not too distant) future.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="pull-request-backlog"&gt;
&lt;h2&gt;Pull request backlog&lt;/h2&gt;
&lt;p&gt;My immediate focus for qutebrowser - and something I know various people are
waiting for - is still the backlog of contributions, some dating back to
December 2017. This is still something I struggle with, as reviewing code takes
a lot of time and focus (perhaps more than writing code myself) and for a long
time, I felt overwhelmed by the backlog.&lt;/p&gt;
&lt;p&gt;Still, two years later, I feel like I'm finally getting a grasp on the issue,
and I feel confident that I can clear things up this time around. The thing which
ended up helping me a lot is creating a GitHub &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/projects/4"&gt;project board&lt;/a&gt; where I'm
organizing pull requests into various categories, depending on (what I think is)
their current state.&lt;/p&gt;
&lt;a class="reference external image-reference" href="https://github.com/qutebrowser/qutebrowser/projects/4"&gt;&lt;img alt="Part of the pull request backlog board" src="/images/prbacklog.png" /&gt;&lt;/a&gt;
&lt;p&gt;This helped me tremendously and resulted in 15 PRs being merged since I opened
the project board 16 days ago. I finally feel like I'm not missing the forest
for the trees anymore. I hope I'll be able to continue the trend of merging
around 1 PR per day on average (at least until I get to the more complex ones),
but there is also another urgent change coming up - more on that in the next
section.&lt;/p&gt;
&lt;p&gt;Thanks again to everyone for your patience. Around once a week or so, people ask
me what the current state of a given pull request is - usually with a different
pull request every time, since different people have different priorities. I
hope the project board will result in more transparency in that regard. Note,
however, that I likely won't be able to say more than that. If there aren't any
open comments on a pull request, I don't know what's missing to get it merged: I
haven't looked at that particular PR in detail yet.&lt;/p&gt;
&lt;p&gt;For older PRs, often there are conflicts with the current master branch, or the
author might have moved on and is not interested in continuing to invest time
into get the PR merged. As a result, I usually request changes and give feedback
on recent PRs, but I will pick up and finish older PRs from where they are
currently.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="session-changes-in-qt-5-15"&gt;
&lt;h2&gt;Session changes in Qt 5.15&lt;/h2&gt;
&lt;p&gt;Loading of sessions has always been a bit of a hack in qutebrowser (though a
hack other QtWebEngine browsers share as well; the original idea is coming from
&lt;a class="reference external" href="https://otter-browser.org/"&gt;Otter Browser&lt;/a&gt;): Since QtWebEngine &lt;a class="reference external" href="https://bugreports.qt.io/browse/QTBUG-60112"&gt;doesn't provide&lt;/a&gt; a way to load a tab's
back/forward history, qutebrowser &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/blob/v1.11.0/qutebrowser/browser/webengine/tabhistory.py"&gt;reconstructs&lt;/a&gt; a binary data stream used by
Qt internally to save/restore history objects.&lt;/p&gt;
&lt;p&gt;Unfortunately, that reverse-engineered binary stream &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/5359"&gt;changed&lt;/a&gt; in the
underlying Chromium version for Qt 5.15, causing it to load &lt;tt class="docutils literal"&gt;about:blank&lt;/tt&gt;
rather than the URLs from the session. When the session is saved again, this
causes the pages originally listed in it to be overwritten. With the change, a
complex &amp;quot;page state&amp;quot; blob is now required to load a tab's history, and this
isn't something we can reconstruct from the data available in session files.&lt;/p&gt;
&lt;p&gt;As a stop-gap measure, I &lt;a class="reference external" href="https://lists.schokokeks.org/pipermail/qutebrowser-announce/2020-April/000080.html"&gt;released&lt;/a&gt; qutebrowser v1.11.0 this week, which works
around the issue by at least opening the current URL for each tab, and also
creates a backup of the session directory on the first start with Qt 5.15.&lt;/p&gt;
&lt;p&gt;Solving the issue properly means adding support for a new history format, which
stores the binary &amp;quot;page state&amp;quot; data needed by Chromium when saving a session,
and restores the data when loading the session.&lt;/p&gt;
&lt;p&gt;At the same time, some other session format changes are planned as well:
Sessions will be saved as a JSON file (rather than YAML), stored inside a zip
file together with the required binary data. After some discussion, this was
deemed the best solution to store the needed data efficiently, while still
keeping session data readable by humans and scripts alike.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="other-bits-and-pieces"&gt;
&lt;h2&gt;Other bits and pieces&lt;/h2&gt;
&lt;p&gt;Finally, there are other smaller changes I'd like to take a look at, for a
variety of reasons: A few are urgent or important for qutebrowser to continue
working, some are important to me personally, others are just a good fit
together with a PR I might be reviewing.&lt;/p&gt;
&lt;p&gt;To make it more transparent what my current focus is, I opened another &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/projects/5"&gt;roadmap
project board&lt;/a&gt; on GitHub, where I'm collecting issues I'm currently focused on
or issues I'd like to tackle.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-road-towards-qt-6-and-qutebrowser-v2-0-0"&gt;
&lt;h2&gt;The road towards Qt 6 and qutebrowser v2.0.0&lt;/h2&gt;
&lt;p&gt;After Qt 5.15 is released in around three weeks, the next release will be
&lt;a class="reference external" href="https://www.youtube.com/watch?v=YmwAeS_ojPA&amp;amp;feature=youtu.be"&gt;Qt 6&lt;/a&gt; - a new major release of Qt with backwards-incompatible changes, something
that happens once all 7-8 years.&lt;/p&gt;
&lt;a class="reference external image-reference" href="https://www.youtube.com/watch?v=YmwAeS_ojPA"&gt;&lt;img alt="Qt 6 Vision graphic" src="/images/qt6.png" /&gt;&lt;/a&gt;
&lt;p&gt;An &lt;a class="reference external" href="https://lists.qt-project.org/pipermail/development/2020-April/039382.html"&gt;initial timeline&lt;/a&gt; was proposed this week, planning a Qt 6 release for
December 2020. Unfortunately, while Qt 4 and 5 were &lt;a class="reference external" href="https://www.qt.io/blog/2014/11/27/qt-4-8-x-support-to-be-extended-for-another-year"&gt;supported in parallel&lt;/a&gt; for
three years, this time around, non-commercial support for Qt 5 &lt;a class="reference external" href="https://www.qt.io/blog/qt-offering-changes-2020"&gt;will end&lt;/a&gt; the
moment Qt 6 is released.&lt;/p&gt;
&lt;p&gt;Therefore, qutebrowser's plan is to be ready for Qt 6 as
soon as possible after it's released (or, ideally, before that). At the same
time, qutebrowser will keep compatibility for Qt 5 for some time (multiple
months, possibly multiple years, depending on the maintenance cost and usage.
Right now it's too early to tell).&lt;/p&gt;
&lt;p&gt;It's planned to use that opportunity to clean up various things for a
qutebrowser v2.0.0 release: There will be various dependency changes with
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/4800"&gt;Python 3.5 support dropped&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/3839"&gt;support for Qt &amp;lt; 5.11 dropped&lt;/a&gt; and some
dependencies being added, swapped out or removed.&lt;/p&gt;
&lt;p&gt;At the same time, there will be various other internal refactorings: I'd like to
get back to looking at &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/30"&gt;extension support&lt;/a&gt; and related refactorings, and also
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/1455"&gt;start using&lt;/a&gt; various automatic code-formatters such as &lt;a class="reference external" href="https://black.readthedocs.io/en/stable/"&gt;black&lt;/a&gt; and &lt;a class="reference external" href="https://github.com/timothycrosley/isort"&gt;isort&lt;/a&gt;.
Those projects weren't around (or not used commonly) when qutebrowser was born,
but I think they would be a good addition to make everyone's lives easier when
working on qutebrowser - just like various Python 3.6+ only features, especially
&lt;a class="reference external" href="https://realpython.com/python-f-strings/"&gt;fstrings&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All that will cause a lot of code churn, so it will only happen after the
majority of the currently open pull requests are merged. I hope that timeline
will work out, and qutebrowser will be a more modern codebase by the end of the
year! See the v2.0.0 &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/milestone/42"&gt;milestone&lt;/a&gt; on GitHub for all planned changes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="qt-company-and-the-kde-free-qt-foundation"&gt;
&lt;h2&gt;Qt Company and the KDE free Qt foundation&lt;/h2&gt;
&lt;a class="reference external image-reference" href="https://community.kde.org/Konqi"&gt;&lt;img alt="Konqi with Qt inside" src="/images/kdeqt.png" /&gt;&lt;/a&gt;
&lt;p&gt;Finally, there was a &lt;a class="reference external" href="https://mail.kde.org/pipermail/kde-community/2020q2/006098.html"&gt;concerning announcement&lt;/a&gt; by the &lt;a class="reference external" href="https://kde.org/community/whatiskde/kdefreeqtfoundation.php"&gt;KDE Free Qt Foundation&lt;/a&gt;
before Easter. In the announcement, they claim that:&lt;/p&gt;
&lt;blockquote&gt;
[...] [The Qt Company] suddenly informed both the KDE e.V. board and the
KDE Free QT Foundation that the economic outlook caused by the Corona virus
puts more pressure on them to increase short-term revenue. As a result, they
are thinking about restricting ALL Qt releases to paid license holders for the
first 12 months. They are aware that this would mean the end of contributions
via Open Governance in practice.&lt;/blockquote&gt;
&lt;p&gt;A day later, The Qt Company &lt;a class="reference external" href="https://www.qt.io/blog/qt-and-open-source"&gt;published&lt;/a&gt; a (very brief) announcement disputing
those claims:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There have been discussions on various internet forums about the future of Qt
open source in the last two days. The contents do not reflect the views or
plans of The Qt Company.&lt;/p&gt;
&lt;p&gt;The Qt Company is proud to be committed to its customers, open source, and
the Qt governance model.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I've asked both sides for clarification (&lt;a class="reference external" href="https://mail.kde.org/pipermail/kde-community/2020q2/006121.html"&gt;KDE&lt;/a&gt;, &lt;a class="reference external" href="https://lists.qt-project.org/pipermail/interest/2020-April/034891.html"&gt;Qt&lt;/a&gt;). This was three weeks
ago, and I haven't heard much more so far.&lt;/p&gt;
&lt;p&gt;If this came true, there aren't many options for qutebrowser and me: Either add
support for a different backend (such as &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Chromium_Embedded_Framework"&gt;Chromium Embedded Framework&lt;/a&gt;) which
means months of work on top of an already giant backlog; or throw the towel.
Having a browser backend with a year delay in security updates is unacceptable
to me, and due to Qt's commercial license terms, purchasing a commercial license
isn't a realistic option either.&lt;/p&gt;
&lt;p&gt;Needless to say, this would be a very hard decision to take. For now, it looks
like The Qt Company just used this to bluff (probably to get some other
provision in their contract changed). That in itself is very concerning and
disheartening, but gives me hope that things can still continue as usual.&lt;/p&gt;
&lt;p&gt;I will update everyone on this matter once (if) there's more to say - until
then, there isn't much more I can do.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="wrapping-up"&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;It's been four months since the last blog post in the &lt;a class="reference external" href="https://blog.qutebrowser.org/"&gt;qutebrowser blog&lt;/a&gt;.
Judging from the length of this post, I probably should post things more often -
sorry about that, and thanks for reading until the end! I hope you are all
healthy and things are going okay, despite the current circumstances. If that's
not the case and you need someone to talk, please don't hesitate to
&lt;a class="reference external" href="mailto:me&amp;#64;the-compiler.org"&gt;reach out to me&lt;/a&gt;! Let's see what the future brings and deal with things as
they come up - both with qutebrowser and in general.&lt;/p&gt;
&lt;/div&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>2019 qutebrowser crowdfunding - reminder</title><link href="https://blog.qutebrowser.org/2019-qutebrowser-crowdfunding-reminder.html" rel="alternate"></link><published>2019-12-30T18:54:38+01:00</published><updated>2019-12-30T18:54:38+01:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2019-12-30:/2019-qutebrowser-crowdfunding-reminder.html</id><summary type="html">&lt;p&gt;Two months ago, I wrote:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Just like in the 2017/2018 crowdfundings, it'll be possible to get t-shirts and stickers again. I'll also add some new swag to the mix :)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Just a quick reminder: If you want physical rewards with the current perk
levels, sign up to the &lt;a class="reference external" href="https://github.com/sponsors/The-Compiler/"&gt;GitHub Sponsors …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Two months ago, I wrote:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Just like in the 2017/2018 crowdfundings, it'll be possible to get t-shirts and stickers again. I'll also add some new swag to the mix :)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Just a quick reminder: If you want physical rewards with the current perk
levels, sign up to the &lt;a class="reference external" href="https://github.com/sponsors/The-Compiler/"&gt;GitHub Sponsors campaign&lt;/a&gt;
before the end of the year.&lt;/p&gt;
&lt;p&gt;Somewhen after 2020 comes around the corner (and probably after my birthday on
the 2nd) I'm going to adjust the perks accordingly.&lt;/p&gt;
&lt;p&gt;-- Florian / &amp;#64;The-Compiler&lt;/p&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>qutebrowser meetup Berlin (2019-11-28)</title><link href="https://blog.qutebrowser.org/qutebrowser-meetup-berlin-2019-11-28.html" rel="alternate"></link><published>2019-11-22T20:55:50+01:00</published><updated>2019-11-22T20:55:50+01:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2019-11-22:/qutebrowser-meetup-berlin-2019-11-28.html</id><summary type="html">&lt;p&gt;I (The-Compiler) am currently in Berlin - I've met with Qt/QtWebEngine
developers at Qt Contributors Summit and had some very interesting development
discussions there. There are some
&lt;a class="reference external" href="https://wiki.qt.io/Category:QtCS2019"&gt;writeups&lt;/a&gt; available in the Qt Wiki.&lt;/p&gt;
&lt;p&gt;Next Thursday (28th) I'd like to have a small qutebrowser user meetup here :)
We'll meet at 19 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I (The-Compiler) am currently in Berlin - I've met with Qt/QtWebEngine
developers at Qt Contributors Summit and had some very interesting development
discussions there. There are some
&lt;a class="reference external" href="https://wiki.qt.io/Category:QtCS2019"&gt;writeups&lt;/a&gt; available in the Qt Wiki.&lt;/p&gt;
&lt;p&gt;Next Thursday (28th) I'd like to have a small qutebrowser user meetup here :)
We'll meet at 19:00 in the
&lt;a class="reference external" href="https://afra-berlin.de/dokuwiki/doku.php?id=en:start"&gt;AfRA Hackerspace&lt;/a&gt;
in Berlin Lichtenberg.&lt;/p&gt;
&lt;p&gt;See (some of) you there, hopefully!&lt;/p&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>2019 qutebrowser crowdfunding with shirts, stickers and more!</title><link href="https://blog.qutebrowser.org/2019-qutebrowser-crowdfunding-with-shirts-stickers-and-more.html" rel="alternate"></link><published>2019-10-30T14:51:15+01:00</published><updated>2019-10-30T14:51:15+01:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2019-10-30:/2019-qutebrowser-crowdfunding-with-shirts-stickers-and-more.html</id><summary type="html">&lt;p&gt;I'm very happy to announce that the next qutebrowser crowdfunding went live
today! o/&lt;/p&gt;
&lt;p&gt;This time, I'm focused on recurring donations via GitHub Sponsors. Those
donations will allow me to work part-time on qutebrowser! Thanks to the GitHub
Matching Fund, all donations (up to $5000 in the first year) will …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I'm very happy to announce that the next qutebrowser crowdfunding went live
today! o/&lt;/p&gt;
&lt;p&gt;This time, I'm focused on recurring donations via GitHub Sponsors. Those
donations will allow me to work part-time on qutebrowser! Thanks to the GitHub
Matching Fund, all donations (up to $5000 in the first year) will be doubled.&lt;/p&gt;
&lt;p&gt;Just like in the 2017/2018 crowdfundings, it'll be possible to get t-shirts and
stickers again. I'll also add some new swag to the mix :)&lt;/p&gt;
&lt;p&gt;You can find all details on my &lt;a class="reference external" href="https://github.com/sponsors/The-Compiler/"&gt;GitHub Sponsors page&lt;/a&gt;
and the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/blob/master/doc/faq.asciidoc#sponsors"&gt;FAQ I've written&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I'm excited for what's to come! If you run into any trouble or have questions,
please &lt;a class="reference external" href="mailto:mail&amp;#64;qutebrowser.org"&gt;let me know&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;-- Florian / &amp;#64;The-Compiler&lt;/p&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>Current qutebrowser roadmap and next crowdfunding</title><link href="https://blog.qutebrowser.org/current-qutebrowser-roadmap-and-next-crowdfunding.html" rel="alternate"></link><published>2019-10-21T15:50:02+02:00</published><updated>2019-10-21T15:50:02+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2019-10-21:/current-qutebrowser-roadmap-and-next-crowdfunding.html</id><summary type="html">&lt;p&gt;More than half a year ago, I posted a qutebrowser &lt;a class="reference external" href="https://lists.schokokeks.org/pipermail/qutebrowser-announce/2019-March/000058.html"&gt;roadmap&lt;/a&gt; - I thought it's
about time for an update on how things are looking at the moment!&lt;/p&gt;
&lt;div class="section" id="upcoming-crowdfunding"&gt;
&lt;h2&gt;Upcoming crowdfunding&lt;/h2&gt;
&lt;p&gt;I finished my Bachelor of Science in September at the &lt;a class="reference external" href="https://www.hsr.ch/en/"&gt;University of Applied
Sciences&lt;/a&gt; in Rapperswil.&lt;/p&gt;
&lt;p&gt;Now I'm employed around 16h …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;More than half a year ago, I posted a qutebrowser &lt;a class="reference external" href="https://lists.schokokeks.org/pipermail/qutebrowser-announce/2019-March/000058.html"&gt;roadmap&lt;/a&gt; - I thought it's
about time for an update on how things are looking at the moment!&lt;/p&gt;
&lt;div class="section" id="upcoming-crowdfunding"&gt;
&lt;h2&gt;Upcoming crowdfunding&lt;/h2&gt;
&lt;p&gt;I finished my Bachelor of Science in September at the &lt;a class="reference external" href="https://www.hsr.ch/en/"&gt;University of Applied
Sciences&lt;/a&gt; in Rapperswil.&lt;/p&gt;
&lt;p&gt;Now I'm employed around 16h/week at the same place, mainly helping out with the
operating systems course (in other words: I spend my time staring at
LaTeX/C/Assembler/Python and teaching students).&lt;/p&gt;
&lt;p&gt;Like already mentioned in the earlier mail, this means I now have a lot more
time than before for working on open-source projects. I'm in the process of
founding my own one-man company and already have some work lined up - but as
soon as everything is set up, I plan to spend much more time on qutebrowser.
Certainly a lot more than what I've been able to during my studies in the past
years.&lt;/p&gt;
&lt;p&gt;However, that means I don't have a lot of recurring income (enough to pay for
rent, food and other bills - but not much more than that). This is why I plan
to start another qutebrowser fundraising very soon. There will be shirts and
stickers available again, as well as some other swag. This time, I'll focus on
recurring donations, but I also plan to offer a way to contribute via one-time
donations instead.&lt;/p&gt;
&lt;p&gt;I got accepted into the Beta of &lt;a class="reference external" href="https://github.com/sponsors"&gt;GitHub Sponsors&lt;/a&gt; - thanks to GitHub's
&lt;a class="reference external" href="https://help.github.com/en/github/supporting-the-open-source-community-with-github-sponsors/about-github-sponsors#about-the-github-sponsors-matching-fund"&gt;matching fund&lt;/a&gt;, all donations (up to a total of $5000) in the first year will
be &lt;em&gt;doubled&lt;/em&gt;. Thus, GitHub Sponsors is the platform I'll use for recurring
donations. For one-time donations, I'll likely offer various options (Stripe,
PayPal, Bitcoin, SEPA Bank Transfers), but I want to get recurring donations up
and running first.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="current-priorities"&gt;
&lt;h2&gt;Current priorities&lt;/h2&gt;
&lt;p&gt;As for qutebrowser itself, my current priorities are the following:&lt;/p&gt;
&lt;div class="section" id="keeping-qutebrowser-up-and-running"&gt;
&lt;h3&gt;Keeping qutebrowser up and running&lt;/h3&gt;
&lt;p&gt;All 6 months, a new Qt feature release is published. Other upgrades (like
Python itself) also need attention from time to time.&lt;/p&gt;
&lt;p&gt;Testing new Qt versions early means that I can report bugs upstream during the
Alpha/Beta phase, which means they'll likely get fixed before a release. Often,
adjustments to qutebrowser itself are also needed to keep it running smoothly
when distributions upgrade their Qt versions.&lt;/p&gt;
&lt;p&gt;In the past few weeks, I spent quite some time dealing with Qt 5.13.1/.2,
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/5013"&gt;Qt 5.14&lt;/a&gt; and &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/4928"&gt;Python 3.8&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A change coming with PyQt 5.14 currently causes trouble with a piece of
qutebrowser (the object registry) which I &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/640"&gt;wanted to remove&lt;/a&gt; for a while now. I
started working on that as well recently, but there's more refactoring work
needed to complete the removal.&lt;/p&gt;
&lt;p&gt;In 2020, Python 2 will (finally!) be retired, but qutebrowser still uses
asciidoc for its documentation, which is unmaintained and based on Python 2.
I intend to switch to &lt;a class="reference external" href="http://www.sphinx-doc.org/"&gt;Sphinx&lt;/a&gt; instead, which should also make it easier to write
(more) nice documentation for qutebrowser.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="getting-the-pull-request-backlog-down"&gt;
&lt;h3&gt;Getting the pull request backlog down&lt;/h3&gt;
&lt;p&gt;Since I had barely enough time to keep things running smoothly during my
studies, a &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/pulls"&gt;backlog&lt;/a&gt; of contributions accumulated.&lt;/p&gt;
&lt;p&gt;There are various new features, bugfixes, performance improvements and a lot of
other great work to find there.&lt;/p&gt;
&lt;p&gt;I find reviewing code to be something that takes more concentrated focus than
writing code, so I can't review PRs all day (I tried!). However, I plan to
spend some time on the PR backlog regularily to get things back to normal
again.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="extension-api"&gt;
&lt;h3&gt;Extension API&lt;/h3&gt;
&lt;p&gt;I want to continue work on the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/30"&gt;extension API&lt;/a&gt; in order to get something released
which is generally available and usable.&lt;/p&gt;
&lt;p&gt;Much of the work on the extension API also ties into the next point - there's a
lot of refactoring needed to get (sometimes quite old) code into a shape where
it is reasonably nice to expose via an extension API.&lt;/p&gt;
&lt;p&gt;I'm aware this is taking a lot longer than originally anticipated. However, I'd
like to avoid exposing code where I anticipate major changes/restructurings -
otherwise, every qutebrowser upgrade would break a lot of extensions every
time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="increasing-maintainability"&gt;
&lt;h3&gt;Increasing maintainability&lt;/h3&gt;
&lt;p&gt;This means reducing technical debt, improving the testsuite (getting it to run
faster and more stable) and introducing mypy / type hints across the codebase.&lt;/p&gt;
&lt;p&gt;In the past few weeks, I added type hints to various qutebrowser modules and
got mypy running with the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--check-untyped-defs&lt;/span&gt;&lt;/tt&gt; flag. That flag tells mypy to
check the bodies of functions which are not type annotated yet, which uncovered
a few subtle bugs and will make upcoming refactorings a lot easier.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="second-look-at-the-config-system"&gt;
&lt;h3&gt;Second look at the config system&lt;/h3&gt;
&lt;p&gt;The new configuration system (introduced in the 2017 crowdfunding) works quite
well - especially compared to the old one. However, some design decisions in it
cause various performance issues. I have some ideas how to change those
internals to make things faster and simpler. In the past few months,
contributors (especially &lt;a class="reference external" href="http://jgkamat.gitlab.io/"&gt;&amp;#64;jgkamat&lt;/a&gt;) have worked on various performance
improvements, but I believe a bigger impact would be possible by changing how
qutebrowser stores configuration data internally.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="tl-dr"&gt;
&lt;h3&gt;tl;dr&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Keeping things running smoothly&lt;/li&gt;
&lt;li&gt;Taking care of open contributions&lt;/li&gt;
&lt;li&gt;Working on the extension API and at the same time refactoring various areas&lt;/li&gt;
&lt;li&gt;Making configuration internals faster and simpler&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I'm excited to see what's to come and how the fundraising turns out. Feedback
very welcome!&lt;/p&gt;
&lt;p&gt;-- Florian / &amp;#64;The-Compiler&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>Crowdfunding 2019 ideas</title><link href="https://blog.qutebrowser.org/crowdfunding-2019-ideas.html" rel="alternate"></link><published>2019-08-05T16:46:38+02:00</published><updated>2019-08-05T16:46:38+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2019-08-05:/crowdfunding-2019-ideas.html</id><summary type="html">&lt;p&gt;Just a quick announcement: I'm planning another crowdfunding in 2019, likely
focused on monthly donations so I can spend 2-3 days a week on qutebrowser
soon!&lt;/p&gt;
&lt;p&gt;With this survey, I want to gather some ideas/opinions about possible
merchandise and some other topics:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://s.cmpl.cc/ideas"&gt;https://s.cmpl.cc/ideas&lt;/a&gt;&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Just a quick announcement: I'm planning another crowdfunding in 2019, likely
focused on monthly donations so I can spend 2-3 days a week on qutebrowser
soon!&lt;/p&gt;
&lt;p&gt;With this survey, I want to gather some ideas/opinions about possible
merchandise and some other topics:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://s.cmpl.cc/ideas"&gt;https://s.cmpl.cc/ideas&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><title>Happy birthday, qutebrowser!</title><link href="https://blog.qutebrowser.org/happy-birthday-qutebrowser.html" rel="alternate"></link><published>2019-08-05T16:46:38+02:00</published><updated>2019-08-05T16:46:38+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2019-08-05:/happy-birthday-qutebrowser.html</id><summary type="html">&lt;p&gt;5 years ago today, this happened:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
commit 11a94957dc038fc27c5ff976197ad2b2d0352d20
Author: Florian Bruhin &amp;lt;git&amp;#64;the-compiler.org&amp;gt;
Date:   Sat Dec 14 22:15:16 2013 +0100

    Initial commit
&lt;/pre&gt;
&lt;p&gt;That's how qutebrowser looked a day after that (and that commit still
seems to run!): &lt;a class="reference external" href="https://imgur.com/a/xoG1r4G"&gt;https://imgur.com/a/xoG1r4G&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Exactly a year later, things …&lt;/p&gt;</summary><content type="html">&lt;p&gt;5 years ago today, this happened:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
commit 11a94957dc038fc27c5ff976197ad2b2d0352d20
Author: Florian Bruhin &amp;lt;git&amp;#64;the-compiler.org&amp;gt;
Date:   Sat Dec 14 22:15:16 2013 +0100

    Initial commit
&lt;/pre&gt;
&lt;p&gt;That's how qutebrowser looked a day after that (and that commit still
seems to run!): &lt;a class="reference external" href="https://imgur.com/a/xoG1r4G"&gt;https://imgur.com/a/xoG1r4G&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Exactly a year later, things were finally ready for a v0.1 release,
after spending two weeks of holidays with fixing bugs.&lt;/p&gt;
&lt;p&gt;Originally, qutebrowser was born because the dwb project was
discontinued: &lt;a class="reference external" href="https://portix.bitbucket.io/dwb/"&gt;https://portix.bitbucket.io/dwb/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That's what I (and many others) were using at the time, and all
alternatives were stuck with an unmaintained WebKit1. Since everything
was using WebKitGTK which was horribly buggy (and WebKit2 in WebKitGTK
lacked a lot of basic features), I decided to start my own thing, based
on Qt instead.&lt;/p&gt;
&lt;p&gt;Back then, there were already discussions about QtWebEngine, and I
originally wondered whether I should just wait with starting qutebrowser
until it's ready. QtWebEngine support was finally added in July 2016, a
lot later than I imagined. Initially, many features didn't work yet, but
in September 2017 it finally became the default backend.&lt;/p&gt;
&lt;p&gt;Later, it turned out that qutebrowser also was a viable alternative for
many Pentadactyl/Vimperator refugees, and qutebrowser got more popular
than I ever imagined.&lt;/p&gt;
&lt;p&gt;So far, there have been:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;17,227 commits&lt;/li&gt;
&lt;li&gt;3,193 issues&lt;/li&gt;
&lt;li&gt;1,273 pull requests&lt;/li&gt;
&lt;li&gt;242 contributors&lt;/li&gt;
&lt;li&gt;47 releases&lt;/li&gt;
&lt;li&gt;2 crowdfundings&lt;/li&gt;
&lt;li&gt;dozens of t-shirts&lt;/li&gt;
&lt;li&gt;thousands of stickers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks a lot to the whole community - y'all are awesome! I never
imagined I would be working on this for so long, or that it'd gain so
much traction. I also didn't believe the crowdfunding thing would work.
You showed me otherwise o/&lt;/p&gt;
&lt;p&gt;Some 3-4 years ago, I noticed there were a couple of big things I'll be
busy with for a while:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Adding a testsuite because things broke a lot&lt;/li&gt;
&lt;li&gt;QtWebEngine&lt;/li&gt;
&lt;li&gt;The new config system&lt;/li&gt;
&lt;li&gt;An extension API&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I'm currently working on the fourth one. Not many new very big tasks
have appeared (except maybe a testsuite which isn't as unreliable and
slow, and some refactorings to keep my sanity when working on the code).&lt;/p&gt;
&lt;p&gt;I'm really looking forward to the point where I can work on smaller
things (and new features) again - for a long time, most of my time was
spent reviewing contributions, fixing bugs, putting out fires with Qt
upgrades, and working on those four major things.&lt;/p&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>CVE-2018-10895: Remote code execution due to CSRF in qutebrowser</title><link href="https://blog.qutebrowser.org/cve-2018-10895-remote-code-execution-due-to-csrf-in-qutebrowser.html" rel="alternate"></link><published>2018-07-11T18:02:29+02:00</published><updated>2018-07-11T18:02:29+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2018-07-11:/cve-2018-10895-remote-code-execution-due-to-csrf-in-qutebrowser.html</id><summary type="html">&lt;div class="section" id="description"&gt;
&lt;h2&gt;Description&lt;/h2&gt;
&lt;p&gt;Due to a CSRF vulnerability affecting the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;qute://settings&lt;/span&gt;&lt;/tt&gt; page, it was
possible for websites to modify qutebrowser settings. Via settings like
&lt;tt class="docutils literal"&gt;editor.command&lt;/tt&gt;, this possibly allowed websites to execute arbitrary code.&lt;/p&gt;
&lt;p&gt;This issue has been assigned &lt;a class="reference external" href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-10895"&gt;CVE-2018-10895&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="affected-versions"&gt;
&lt;h2&gt;Affected versions&lt;/h2&gt;
&lt;p&gt;The issue was introduced in v1.0.0, as …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="section" id="description"&gt;
&lt;h2&gt;Description&lt;/h2&gt;
&lt;p&gt;Due to a CSRF vulnerability affecting the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;qute://settings&lt;/span&gt;&lt;/tt&gt; page, it was
possible for websites to modify qutebrowser settings. Via settings like
&lt;tt class="docutils literal"&gt;editor.command&lt;/tt&gt;, this possibly allowed websites to execute arbitrary code.&lt;/p&gt;
&lt;p&gt;This issue has been assigned &lt;a class="reference external" href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-10895"&gt;CVE-2018-10895&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="affected-versions"&gt;
&lt;h2&gt;Affected versions&lt;/h2&gt;
&lt;p&gt;The issue was introduced in v1.0.0, as part of commit &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/ffc29ee"&gt;ffc29ee&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It was fixed in the v1.4.1 release, in commit &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/43e58ac865ff862c2008c510fc5f7627e10b4660"&gt;43e58ac&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All releases between v1.0.0 and v1.4.0 (inclusive) are affected.
Backported patches are available, but no additional releases are planned:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/ff686ff7f395d83e5ac48507ecfae0b0e97a61ef"&gt;v1.1.x&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/c3361c31b370140f323e481dd455450b1e74c099"&gt;v1.2.x&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/c2ff32d92ba9bf40ff53498ee04a4124d4993c85"&gt;v1.3.x&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/22148ce488da52e8a0e01ed937c0cfdb24d34775"&gt;v1.4.x&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/43e58ac865ff862c2008c510fc5f7627e10b4660"&gt;master&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(add .patch to the URL to get patches)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="timeline"&gt;
&lt;h2&gt;Timeline&lt;/h2&gt;
&lt;p&gt;2018-07-09: I was made aware of the original issue privately (initially
believed by the reporter to only be a DoS issue), developed a fix and contacted
the distros Openwall mailinglist to organize a disclosure date to give
distributions time to coordinate releasing of a fix.&lt;/p&gt;
&lt;p&gt;2018-07-10: Slightly updated patch sent to the distros mailinglist.&lt;/p&gt;
&lt;p&gt;2018-07-11: Public disclosure.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="mitigation"&gt;
&lt;h2&gt;Mitigation&lt;/h2&gt;
&lt;p&gt;Please upgrade to v1.4.1 or apply the patches above.&lt;/p&gt;
&lt;p&gt;Note that disabling loading of &lt;tt class="docutils literal"&gt;autoconfig.yml&lt;/tt&gt; is not a suitable remedy, since
settings are still applied until the next restart.&lt;/p&gt;
&lt;p&gt;As a workaround, it's possible to patch out the vulnerable code via a
&lt;tt class="docutils literal"&gt;config.py&lt;/tt&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;qutebrowser.browser&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;qutescheme&lt;/span&gt;
&lt;span class="n"&gt;qutescheme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_qute_settings_set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;text/html&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While there is no known exploit for this in the wild, users are advised to
check their &lt;tt class="docutils literal"&gt;autoconfig.yml&lt;/tt&gt; file (located in the config folder shown in
&lt;tt class="docutils literal"&gt;:version&lt;/tt&gt;) for any unwanted modifications.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="credits"&gt;
&lt;h2&gt;Credits&lt;/h2&gt;
&lt;p&gt;Thanks to:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;toofar for reporting the initial issue.&lt;/li&gt;
&lt;li&gt;Allan Sandfeld Jensen (carewolf) and Jüri Valdmann (juvaldma) of The Qt
Company for their assistance with triaging and fixing the issue.&lt;/li&gt;
&lt;li&gt;toofar and Jay Kamat (jgkamat) for reviewing the patch.&lt;/li&gt;
&lt;li&gt;Morten Linderud (Foxboron) for suggestions on how to disclose this
properly.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="links"&gt;
&lt;h2&gt;Links&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/4060"&gt;https://github.com/qutebrowser/qutebrowser/issues/4060&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://lists.schokokeks.org/pipermail/qutebrowser-announce/2018-July/000048.html"&gt;https://lists.schokokeks.org/pipermail/qutebrowser-announce/2018-July/000048.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>qutebrowser v1.3.3 released (security update!)</title><link href="https://blog.qutebrowser.org/qutebrowser-v133-released-security-update.html" rel="alternate"></link><published>2018-06-22T02:04:18+02:00</published><updated>2018-06-22T02:04:18+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2018-06-22:/qutebrowser-v133-released-security-update.html</id><summary type="html">&lt;p&gt;I've just released qutebrowser v1.3.3, which fixes an XSS vulnerability
on the qute://history page (:history).&lt;/p&gt;
&lt;p&gt;qutebrowser is a keyboard driven browser with a vim-like, minimalistic
interface. It's written using PyQt and cross-platform.&lt;/p&gt;
&lt;p&gt;The vulnerability allowed websites to inject HTML into the page via a
crafted title tag …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I've just released qutebrowser v1.3.3, which fixes an XSS vulnerability
on the qute://history page (:history).&lt;/p&gt;
&lt;p&gt;qutebrowser is a keyboard driven browser with a vim-like, minimalistic
interface. It's written using PyQt and cross-platform.&lt;/p&gt;
&lt;p&gt;The vulnerability allowed websites to inject HTML into the page via a
crafted title tag. This could allow them to steal your browsing history.&lt;/p&gt;
&lt;p&gt;If you're currently unable to upgrade, avoid using :history.&lt;/p&gt;
&lt;p&gt;A CVE request for this issue is pending, see the relevant issue for updates:
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/4011"&gt;https://github.com/qutebrowser/qutebrowser/issues/4011&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The issue was introduced in March 2017 and part of the v0.11.0 release:
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/845f21b275bf438eccd7854f7f5401233ec6719a"&gt;https://github.com/qutebrowser/qutebrowser/commit/845f21b275bf438eccd7854f7f5401233ec6719a&lt;/a&gt;
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/1179ee7a937fb31414d77d9970bac21095358449"&gt;https://github.com/qutebrowser/qutebrowser/commit/1179ee7a937fb31414d77d9970bac21095358449&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The patch applies cleanly to v1.2.x and v1.1.x (but I do not plan to do
any updated releases of those):
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/5a7869f2feaa346853d2a85413d6527c87ef0d9f.patch"&gt;https://github.com/qutebrowser/qutebrowser/commit/5a7869f2feaa346853d2a85413d6527c87ef0d9f.patch&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It does &lt;em&gt;not&lt;/em&gt; apply to v1.0.x and v0.11.x. If you need a backport,
please let me know, but especially on v0.11.x you'll probably have a lot
of other security issues due to an outdated QtWebKit anyways.&lt;/p&gt;
&lt;p&gt;I plan to release v1.4.0 later this week (once PyQt 5.11 is out), but
since the bug was opened publicly, I decided to do an immediate bugfix
release. As a reminder, for security-relevant bugs, please contact me
directly at mail at qutebrowser.org.&lt;/p&gt;
&lt;p&gt;Other bugfixes in this release:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Crash in a workaround for a Qt 5.11 bug in rare circumstances.&lt;/li&gt;
&lt;li&gt;Workaround for a Qt bug which preserves searches between page loads.&lt;/li&gt;
&lt;li&gt;In v1.3.2 a dependency on the &lt;cite&gt;PyQt5.QtQuickWidgets&lt;/cite&gt; module was accidentally
introduced. Since that module isn't packaged everywhere, it's been removed
again.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sorry for the trouble!&lt;/p&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>qutebrowser v1.2.0 released!</title><link href="https://blog.qutebrowser.org/qutebrowser-v120-released.html" rel="alternate"></link><published>2018-03-09T23:28:43+01:00</published><updated>2018-03-09T23:28:43+01:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2018-03-09:/qutebrowser-v120-released.html</id><summary type="html">&lt;p&gt;I'm happy to announce that I just released qutebrowser v1.2.0!&lt;/p&gt;
&lt;p&gt;qutebrowser is a keyboard driven browser with a vim-like, minimalistic
interface. It's written using PyQt and cross-platform.&lt;/p&gt;
&lt;p&gt;This release comes with a long changelog, but the most interesting changes are
probably initial support for per-domain settings (I've had …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I'm happy to announce that I just released qutebrowser v1.2.0!&lt;/p&gt;
&lt;p&gt;qutebrowser is a keyboard driven browser with a vim-like, minimalistic
interface. It's written using PyQt and cross-platform.&lt;/p&gt;
&lt;p&gt;This release comes with a long changelog, but the most interesting changes are
probably initial support for per-domain settings (I've had JavaScript disabled
globally for a while myself now) and a big refactoring of how keybindings are
handled (allowing for emacs-like key chains with modifiers).&lt;/p&gt;
&lt;p&gt;Here's the complete changelog:&lt;/p&gt;
&lt;div class="section" id="added"&gt;
&lt;h2&gt;Added&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Initial implementation of per-domain settings:&lt;ul&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:set&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:config-cycle&lt;/span&gt;&lt;/tt&gt; now have a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-u&lt;/span&gt;&lt;/tt&gt;/&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--pattern&lt;/span&gt;&lt;/tt&gt; argument taking a URL match pattern for supported settings.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;config.set&lt;/tt&gt; in &lt;tt class="docutils literal"&gt;config.py&lt;/tt&gt; now takes a third argument which is the pattern.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;with &lt;span class="pre"&gt;config.pattern('...')&lt;/span&gt; as p:&lt;/tt&gt; context manager for &lt;tt class="docutils literal"&gt;config.py&lt;/tt&gt; to use the shorthand syntax with a pattern.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;tsh&lt;/tt&gt; keybinding to toggle scripts for the current host. With a capital &lt;tt class="docutils literal"&gt;S&lt;/tt&gt;, the toggle is saved. With a capital &lt;tt class="docutils literal"&gt;H&lt;/tt&gt;, subdomains are included. With &lt;tt class="docutils literal"&gt;u&lt;/tt&gt; instead of &lt;tt class="docutils literal"&gt;h&lt;/tt&gt;, the exact current URL is used.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;tph&lt;/tt&gt; keybinding to toggle plugins, with the same additional binding described above.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;New QtWebEngine features:&lt;ul&gt;
&lt;li&gt;Caret/visual mode&lt;/li&gt;
&lt;li&gt;Authentication via ~/.netrc&lt;/li&gt;
&lt;li&gt;Retrying downloads with Qt 5.10 or newer&lt;/li&gt;
&lt;li&gt;Hinting and other features inside same-origin frames&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;New flags for existing commands:&lt;ul&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:session-load&lt;/span&gt;&lt;/tt&gt; has a new &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--delete&lt;/span&gt;&lt;/tt&gt; flag which deletes the session after loading it.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--no-last&lt;/span&gt;&lt;/tt&gt; flag for &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:tab-focus&lt;/span&gt;&lt;/tt&gt; to not focus the last tab when focusing the currently focused one.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--edit&lt;/span&gt;&lt;/tt&gt; flag for &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:view-source&lt;/span&gt;&lt;/tt&gt; to open the source in an external editor.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--select&lt;/span&gt;&lt;/tt&gt; flag for &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:follow-hint&lt;/span&gt;&lt;/tt&gt; which acts like the given string was entered but doesn't necessary follow the hint.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;New special pages:&lt;ul&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;qute://bindings&lt;/span&gt;&lt;/tt&gt; (opened via &lt;tt class="docutils literal"&gt;:bind&lt;/tt&gt;) which shows all keybindings.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;qute://tabs&lt;/span&gt;&lt;/tt&gt; (opened via &lt;tt class="docutils literal"&gt;:buffer&lt;/tt&gt;) which lists all tabs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;New settings:&lt;ul&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;statusbar.widgets&lt;/tt&gt; to configure which widgets should be shown in which order in the statusbar.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;tabs.mode_on_change&lt;/tt&gt; which replaces &lt;tt class="docutils literal"&gt;tabs.persist_mode_on_change&lt;/tt&gt;. It can now be set to &lt;tt class="docutils literal"&gt;restore&lt;/tt&gt; which remembers input modes (input/passthrough) per tab.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;input.insert_mode.auto_enter&lt;/tt&gt; which makes it possible to disable entering insert mode automatically when an editable element was clicked. Together with &lt;tt class="docutils literal"&gt;input.forward_unbound_keys&lt;/tt&gt;, this should allow for emacs-like &amp;quot;modeless&amp;quot; keybindings.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:prompt-yank&lt;/span&gt;&lt;/tt&gt; command (bound to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Alt-y&lt;/span&gt;&lt;/tt&gt; by default) to yank URLs referenced in prompts.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;hostblock_blame&lt;/tt&gt; script which was removed in v1.0 was updated for the new config and re-added.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;cycle-inputs.js&lt;/span&gt;&lt;/tt&gt; script in &lt;tt class="docutils literal"&gt;scripts/&lt;/tt&gt; which can be used with &lt;tt class="docutils literal"&gt;:jseval &lt;span class="pre"&gt;-f&lt;/span&gt;&lt;/tt&gt; to cycle through inputs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="changed"&gt;
&lt;h2&gt;Changed&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Complete refactoring of key input handling, with various effects:&lt;ul&gt;
&lt;li&gt;emacs-like keychains such as &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;&amp;lt;Ctrl-X&amp;gt;&amp;lt;Ctrl-C&amp;gt;&lt;/span&gt;&lt;/tt&gt; can now be bound.&lt;/li&gt;
&lt;li&gt;Key chains can now be bound in any mode (this allows binding unused keys in hint mode).&lt;/li&gt;
&lt;li&gt;Yes/no prompts don't use keybindings from the &lt;tt class="docutils literal"&gt;prompt&lt;/tt&gt; section anymore, they have their own &lt;tt class="docutils literal"&gt;yesno&lt;/tt&gt; section instead.&lt;/li&gt;
&lt;li&gt;Trying to bind invalid keys now shows an error.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;bindings.default&lt;/tt&gt; setting can now only be set in a &lt;tt class="docutils literal"&gt;config.py&lt;/tt&gt;, and existing values in &lt;tt class="docutils literal"&gt;autoconfig.yml&lt;/tt&gt; are ignored.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Improvements for GreaseMonkey support:&lt;ul&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&amp;#64;include&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&amp;#64;exclude&lt;/tt&gt; now support regex matches. With QtWebEngine and Qt 5.8 and newer, Qt handles the matching, but similar functionality will be added in Qt 5.11.&lt;/li&gt;
&lt;li&gt;Support for &lt;tt class="docutils literal"&gt;&amp;#64;requires&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Support for the GreaseMonkey 4.0 API&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The sqlite history now uses write-ahead logging which should be a performance and stability improvement.&lt;/li&gt;
&lt;li&gt;When an editor is spawned with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:open-editor&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:config-edit&lt;/span&gt;&lt;/tt&gt;, the changes are now applied as soon as the file is saved in the editor.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;hist_importer.py&lt;/tt&gt; script now only imports URL schemes qutebrowser can handle.&lt;/li&gt;
&lt;li&gt;Deleting a prefix (&lt;tt class="docutils literal"&gt;:&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;/&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;?&lt;/tt&gt;) via backspace now leaves command mode.&lt;/li&gt;
&lt;li&gt;Angular 1 elements and &lt;tt class="docutils literal"&gt;&amp;lt;summary&amp;gt;&lt;/tt&gt;/&lt;tt class="docutils literal"&gt;&amp;lt;details&amp;gt;&lt;/tt&gt; now get hints assigned.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:tab-only&lt;/span&gt;&lt;/tt&gt; with pinned tabs now still closes unpinned tabs.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;url.incdec_segments&lt;/tt&gt; option now also can take &lt;tt class="docutils literal"&gt;port&lt;/tt&gt; as possible segment.&lt;/li&gt;
&lt;li&gt;QtWebEngine: &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:view-source&lt;/span&gt;&lt;/tt&gt; now uses Chromium's &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;view-source:&lt;/span&gt;&lt;/tt&gt; scheme.&lt;/li&gt;
&lt;li&gt;Tabs now show their full title as tooltip.&lt;/li&gt;
&lt;li&gt;When there are multiple unknown keys in a autoconfig.yml, they now all get reported in one error.&lt;/li&gt;
&lt;li&gt;More performance improvements when opening/closing many tabs.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;:version&lt;/tt&gt; page now has a button to pastebin the information.&lt;/li&gt;
&lt;li&gt;Replacements like &lt;tt class="docutils literal"&gt;{url}&lt;/tt&gt; can now be escaped as &lt;tt class="docutils literal"&gt;{{url}}&lt;/tt&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="fixed"&gt;
&lt;h2&gt;Fixed&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;QtWebEngine bugfixes:&lt;ul&gt;
&lt;li&gt;Improved fullscreen handling with Qt 5.10.&lt;/li&gt;
&lt;li&gt;Hinting and scrolling now works properly on special &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;view-source:&lt;/span&gt;&lt;/tt&gt; pages.&lt;/li&gt;
&lt;li&gt;Scroll positions are now restored correctly from sessions.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:follow-selected&lt;/span&gt;&lt;/tt&gt; should now work in more cases with Qt &amp;gt; 5.10.&lt;/li&gt;
&lt;li&gt;Incremental search now flickers less and doesn't move to the second result when pressing Enter.&lt;/li&gt;
&lt;li&gt;Keys like &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Ctrl-V&lt;/span&gt;&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Shift-Insert&lt;/span&gt;&lt;/tt&gt; are now correctly handled/filtered with Qt 5.10.&lt;/li&gt;
&lt;li&gt;Fixed hangs/segfaults on exit with Qt 5.10.1.&lt;/li&gt;
&lt;li&gt;Fixed favicons sometimes getting cleared with Qt 5.10.&lt;/li&gt;
&lt;li&gt;Qt download objects are now cleaned up properly when a download is removed.&lt;/li&gt;
&lt;li&gt;JavaScript messages are now not double-HTML escaped anymore on Qt &amp;lt; 5.11&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;QtWebKit bugfixes:&lt;ul&gt;
&lt;li&gt;Fixed GreaseMonkey-related crashes.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:view-source&lt;/span&gt;&lt;/tt&gt; now displays a valid URL.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;URLs containing ampersands and other special chars are now shown correctly when filtering them in the completion.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:bookmark-add&lt;/span&gt; &amp;quot;&amp;quot; foo&lt;/tt&gt; can now be used to save the current URL with a custom title.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:spawn &lt;span class="pre"&gt;-o&lt;/span&gt;&lt;/tt&gt; now waits until the process has finished before trying to show the output. Previously, it incorrectly showed the previous output immediately.&lt;/li&gt;
&lt;li&gt;Suspended pages now should always load the correct page when being un-suspended.&lt;/li&gt;
&lt;li&gt;Exception types are now shown properly with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:config-source&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:config-edit&lt;/span&gt;&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;When using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:bookmark-add&lt;/span&gt; &lt;span class="pre"&gt;--toggle&lt;/span&gt;&lt;/tt&gt;, bookmarks are now saved properly.&lt;/li&gt;
&lt;li&gt;Crash when opening an invalid URL from an application on macOS.&lt;/li&gt;
&lt;li&gt;Crash with an empty &lt;tt class="docutils literal"&gt;completion.timestamp_format&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;Crash when &lt;tt class="docutils literal"&gt;completion.min_chars&lt;/tt&gt; is set in some cases.&lt;/li&gt;
&lt;li&gt;HTML/JS resource files are now read into RAM on start to avoid crashes when changing qutebrowser versions while it's open.&lt;/li&gt;
&lt;li&gt;Setting &lt;tt class="docutils literal"&gt;bindings.key_mappings&lt;/tt&gt; to an empty value is now allowed.&lt;/li&gt;
&lt;li&gt;Bindings to an empty commands are now ignored rather than crashing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="removed"&gt;
&lt;h2&gt;Removed&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;QUTE_SELECTED_HTML&lt;/tt&gt; is now not set for userscripts anymore except when called via hints.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;qutebrowser_viewsource&lt;/tt&gt; userscript has been removed as &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:view-source&lt;/span&gt; &lt;span class="pre"&gt;--edit&lt;/span&gt;&lt;/tt&gt; can now be used.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;tabs.persist_mode_on_change&lt;/tt&gt; setting has been removed and replaced by &lt;tt class="docutils literal"&gt;tabs.mode_on_change&lt;/tt&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>T-Shirts shipped, initial implementation of per-domain settings</title><link href="https://blog.qutebrowser.org/t-shirts-shipped-initial-implementation-of-per-domain-settings.html" rel="alternate"></link><published>2018-02-20T08:14:44+01:00</published><updated>2018-02-20T08:14:44+01:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2018-02-20:/t-shirts-shipped-initial-implementation-of-per-domain-settings.html</id><summary type="html">&lt;p&gt;Last Saturday, I finally managed to ship all t-shirts with some much appreciated
help from a friend and my SO! You should hopefully get yours soon (I'd imagine
starting today for people from Germany). &lt;strong&gt;I'd really appreciate it if you could
send me a quick mail (mail&amp;#64;qutebrowser.org) or …&lt;/strong&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last Saturday, I finally managed to ship all t-shirts with some much appreciated
help from a friend and my SO! You should hopefully get yours soon (I'd imagine
starting today for people from Germany). &lt;strong&gt;I'd really appreciate it if you could
send me a quick mail (mail&amp;#64;qutebrowser.org) or ping me on IRC (#qutebrowser on
Freenode) if yours arrived&lt;/strong&gt; (and in what country you are).That helps me to keep
track of how things look, since all shirts are sent without tracking.&lt;/p&gt;
&lt;p&gt;We ended up bringing a big ~18kg parcel to the post office containing 55
envelopes:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/2017_shirts_1.jpg"&gt;&lt;img alt="A big box of packed t-shirts" src="/images/2017_shirts_1_small.jpg" /&gt;&lt;/a&gt;
&lt;a class="reference external image-reference" href="/images/2017_shirts_2.jpg"&gt;&lt;img alt="A big box of packed t-shirts" src="/images/2017_shirts_2_small.jpg" /&gt;&lt;/a&gt;
&lt;p&gt;As usual, not everything went quite to plan - here's a list of the mistakes we
thankfully caught:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;I accidentally discarded a sheet of labels which still had three labels on it.
This was caught by counting the envelopes at the end, and easy to re-print.&lt;/li&gt;
&lt;li&gt;Someone almost got a lady-cut M instead of a regular-cut one. Really glad we
caught that one before it was too late.&lt;/li&gt;
&lt;li&gt;The glue on the padded envelopes didn't really hold well, so one opened while
we were handling them. It turns out others were really close to opening as
well - we were really lucky this happened while they were still at our place,
and fixed it with some additional tape.&lt;/li&gt;
&lt;li&gt;It turns out a &amp;quot;big letter&amp;quot; shipped worldwide has a bigger maximum size than
the same thing to Germany - there, a &amp;quot;maxi letter&amp;quot; is apparently needed. We
only found out at the post office, and had to put some additional stamps on
there - thankfully, this was only on 8 envelopes going to Germany.&lt;/li&gt;
&lt;li&gt;While I &lt;a class="reference external" href="https://github.com/qutebrowser/crowdfunding-tools/blob/master/internetmarke-annotate/annotate.py"&gt;wrote some code&lt;/a&gt; to add additional text to the labels telling us what
to pack (which streamlined things extremely compared to last year!), I forgot
that I promised 10/15/20 stickers depending on the pledge levels. The ones
with 20 stickers were easy to find (as they have two t-shirts), for others
there was a pragmatic solution: Simply giving 15 stickers to everyone :)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I do hope everything else went according to plan, but if something is wrong with
what you got, please contact me.&lt;/p&gt;
&lt;p&gt;I've also been hard at work on per-domain settings, and I have a first prototype
to show:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/per_domain_settings.gif"&gt;&lt;img alt="Proof-of-concept for per-domain settings" src="/images/per_domain_settings_small.gif" /&gt;&lt;/a&gt;
&lt;p&gt;It's in the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/compare/per-url"&gt;per-url branch&lt;/a&gt;, but not quite ready yet - if you want to try it,
make sure to make a backup of your config directory first. As you can see, it
requires a reload to apply the settings currently. I'll look into avoiding that
where possible, but I can't quite tell yet to what extend that will be possible.&lt;/p&gt;
</content></entry><entry><title>Current state of per-domain settings</title><link href="https://blog.qutebrowser.org/current-state-of-per-domain-settings.html" rel="alternate"></link><published>2017-11-06T22:30:08+01:00</published><updated>2017-11-06T22:30:08+01:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2017-11-06:/current-state-of-per-domain-settings.html</id><summary type="html">&lt;p&gt;Since I've been asked for the current state of per-domain various times, here's a quick overview:&lt;/p&gt;
&lt;div class="section" id="history"&gt;
&lt;h2&gt;History&lt;/h2&gt;
&lt;p&gt;I've planned to implement this as part of the recent &lt;a class="reference external" href="https://www.kickstarter.com/projects/the-compiler/qutebrowser-v10-with-per-domain-settings"&gt;crowdfunding&lt;/a&gt;,
but things have taken a bit longer than expected there (and I like doing things
properly rather than doing more but half-baked …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Since I've been asked for the current state of per-domain various times, here's a quick overview:&lt;/p&gt;
&lt;div class="section" id="history"&gt;
&lt;h2&gt;History&lt;/h2&gt;
&lt;p&gt;I've planned to implement this as part of the recent &lt;a class="reference external" href="https://www.kickstarter.com/projects/the-compiler/qutebrowser-v10-with-per-domain-settings"&gt;crowdfunding&lt;/a&gt;,
but things have taken a bit longer than expected there (and I like doing things
properly rather than doing more but half-baked). See &lt;a class="reference external" href="https://blog.qutebrowser.org/refactoring-more-things-a-working-yaml-config-and-more.html"&gt;these&lt;/a&gt;
two &lt;a class="reference external" href="https://blog.qutebrowser.org/new-config-merged.html"&gt;blog posts&lt;/a&gt;
(especially the last sections) for more context. Because of that, I haven't been
able to work on this full-time like I originally wanted.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="current-status"&gt;
&lt;h2&gt;Current status&lt;/h2&gt;
&lt;p&gt;There's some &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/27#issuecomment-338477722"&gt;thoughts&lt;/a&gt;
on how this affects various parts of qutebrowser, but there's no code yet.&lt;/p&gt;
&lt;p&gt;However, the requirements to get started on this (the new config) are finally
out of the way, even though it took almost three years because I was mostly busy
with tests and QtWebEngine stuff before starting work on the new config.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-i-m-busy-with"&gt;
&lt;h2&gt;What I'm busy with&lt;/h2&gt;
&lt;p&gt;Currently, there's a couple things keeping me busy:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;My studies (and other real-life stuff). This will always have priority over
qutebrowser work, and the workload is a lot bigger than I anticipated, as
there's a lot of project work I need to do during the semester (something like
13 projects, compared to 2 or so last semester) to be allowed for the exams.&lt;/li&gt;
&lt;li&gt;Taking care of the T-Shirts and other rewards (other than stickers) for the
crowdfunding. I postponed this during the full-time work so I could finish the
new config, but this takes a lot more time than one might imagine.&lt;/li&gt;
&lt;li&gt;Taking care of contributions - a lot of nice contributions (such as
GreaseMonkey support) are currently in the pipeline, but taking care of
reviewing those and &amp;quot;mentoring&amp;quot; people also takes a fair amount of time.&lt;/li&gt;
&lt;li&gt;&amp;quot;Support&amp;quot; - meaning everything related to helping in people in the IRC
channel, Reddit, private mails, issues on GitHub, etc. It might not seem like
much, but it's easily an hour or so per week as well. It's not something I
want to do less off though, as I think it's very important (and it's also a
nice break from all the coding and writing I'm doing for my studies).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the time remaining for qutebrowser work after that, I really don't have the
time nor mental energy to work on something big like this I'm afraid. If I push
code changes to qutebrowser myself lately, it's either some important bug fixes,
or just something I felt like would be &lt;em&gt;fun&lt;/em&gt; for once again.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="future"&gt;
&lt;h2&gt;Future&lt;/h2&gt;
&lt;p&gt;So, as you can imagine, I can't really give you an ETA for this (and I've
historically never done so for work I do in my free time, because I just end up
making false promises anyways).&lt;/p&gt;
&lt;p&gt;In ~Febuary, I have two weeks of holidays after exams, and I &lt;em&gt;might&lt;/em&gt; be able to
tackle this then. I might be able to look at (the basics of) it before that,
when I feel like I need a break from other coding and can work on something
bigger again. Or it might need to wait longer, because those are holidays after
all, and after three weeks of writing exams, maybe I'll just need a break for
once.&lt;/p&gt;
&lt;p&gt;I can imagine some people aren't really happy with this situation, and I'm not
really either (I still really want NoScript/uMatrix-like functionality myself!).
But that's just how things turned out I'm afraid. I did what I could during the
crowdfunded time.&lt;/p&gt;
&lt;/div&gt;
</content></entry><entry><title>qutebrowser v1.0.0 released!</title><link href="https://blog.qutebrowser.org/qutebrowser-v100-released.html" rel="alternate"></link><published>2017-10-12T11:16:42+02:00</published><updated>2017-10-13T09:52:50+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2017-10-12:/qutebrowser-v100-released.html</id><summary type="html">&lt;p&gt;I'm delighted to announce that I just released qutebrowser v1.0.0!&lt;/p&gt;
&lt;p&gt;qutebrowser is a keyboard driven browser with a vim-like, minimalistic
interface. It's written using PyQt and cross-platform.&lt;/p&gt;
&lt;p&gt;This release comes with many big breaking changes such as the new config and
QtWebEngine by default, so please take a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I'm delighted to announce that I just released qutebrowser v1.0.0!&lt;/p&gt;
&lt;p&gt;qutebrowser is a keyboard driven browser with a vim-like, minimalistic
interface. It's written using PyQt and cross-platform.&lt;/p&gt;
&lt;p&gt;This release comes with many big breaking changes such as the new config and
QtWebEngine by default, so please take a look at the changelog.&lt;/p&gt;
&lt;p&gt;As announced previously, per-domain settings unfortunately didn't make it into
v1.0.0 - it's the next thing I plan on tackling. However, there's more than
enough big things in v1.0.0! :)&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;edit:&lt;/strong&gt; I just released v1.0.1 which fixes three bugs introduced in v1.0.0:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Fixed starting after customizing &lt;cite&gt;fonts.tabs&lt;/cite&gt; or &lt;cite&gt;fonts.debug_console&lt;/cite&gt;.&lt;/li&gt;
&lt;li&gt;Fixed starting with old PyQt versions compiled against newer Qt versions.&lt;/li&gt;
&lt;li&gt;Fixed check for PyQt version to correctly enforce 5.7 (not 5.2).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The full changelog for v1.0.0:&lt;/p&gt;
&lt;div class="section" id="major-changes"&gt;
&lt;h2&gt;Major changes&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Dependency changes:&lt;ul&gt;
&lt;li&gt;Support for legacy QtWebKit (before 5.212 which is
&lt;a class="reference external" href="https://github.com/annulen/webkit/wiki"&gt;distributed independently from Qt&lt;/a&gt;)
is dropped.&lt;/li&gt;
&lt;li&gt;Support for Python 3.4 is dropped.&lt;/li&gt;
&lt;li&gt;Support for Qt before 5.7.1 and PyQt before 5.7 is dropped.&lt;/li&gt;
&lt;li&gt;New dependency on the QtSql module and Qt sqlite support.&lt;/li&gt;
&lt;li&gt;New dependency on the &lt;a class="reference external" href="http://www.attrs.org/"&gt;attrs&lt;/a&gt; project (packaged as
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;python-attr&lt;/span&gt;&lt;/tt&gt; in some distributions).&lt;/li&gt;
&lt;li&gt;The depedency on PyOpenGL (when using QtWebEngine) got removed. Note
that PyQt5.QtOpenGL is still a dependency.&lt;/li&gt;
&lt;li&gt;PyQt5.QtOpenGL is now always required, even with QtWebKit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The QtWebEngine backend is now used by default. Note this means that
QtWebEngine now should be a required dependency, and QtWebKit (if new enough)
should be changed to an optional dependency.&lt;/li&gt;
&lt;li&gt;Completely rewritten configuration system which ignores the old config file.
See &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;qute://help/configuring.html&lt;/span&gt;&lt;/tt&gt; for details.&lt;/li&gt;
&lt;li&gt;Various documentation files got moved to the doc/ subfolder; &lt;tt class="docutils literal"&gt;qutebrowser.desktop&lt;/tt&gt; got moved to misc/.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:set&lt;/tt&gt; now doesn't support toggling/cycling values anymore, that functionality got moved to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:config-cycle&lt;/span&gt;&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;New completion engine based on sqlite, which allows to complete
the entire browsing history. The default for
&lt;tt class="docutils literal"&gt;completion.web_history_max_items&lt;/tt&gt; got changed to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-1&lt;/span&gt;&lt;/tt&gt; (unlimited). If the
completion is too slow on your machine, try setting it to a few 1000 items.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="added"&gt;
&lt;h2&gt;Added&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;QtWebEngine: Spell checking support, see the &lt;tt class="docutils literal"&gt;spellcheck.languages&lt;/tt&gt; setting.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;qt.args&lt;/tt&gt; setting to pass additional arguments to Qt/Chromium.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;backend&lt;/tt&gt; setting to select the backend to use.
Together with the previous setting, this should make most wrapper scripts
unnecessary.&lt;/li&gt;
&lt;li&gt;qutebrowser can now be set as the default browser on macOS.&lt;/li&gt;
&lt;li&gt;New config commands:&lt;ul&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:config-cycle&lt;/span&gt;&lt;/tt&gt; to cycle an option between multiple values.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:config-unset&lt;/span&gt;&lt;/tt&gt; to remove a configured option.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:config-clear&lt;/span&gt;&lt;/tt&gt; to remove all configured options.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:config-source&lt;/span&gt;&lt;/tt&gt; to (re-)read a &lt;tt class="docutils literal"&gt;config.py&lt;/tt&gt; file.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:config-edit&lt;/span&gt;&lt;/tt&gt; to open the &lt;tt class="docutils literal"&gt;config.py&lt;/tt&gt; file in an editor.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:config-write-py&lt;/span&gt;&lt;/tt&gt; to write a &lt;tt class="docutils literal"&gt;config.py&lt;/tt&gt; template file.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;:version&lt;/tt&gt; command which opens &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;qute://version&lt;/span&gt;&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;New back/forward indicator in the statusbar.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;bindings.key_mappings&lt;/tt&gt; setting to map keys to other keys.&lt;/li&gt;
&lt;li&gt;QtWebEngine: Support for proxy authentication.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="changed"&gt;
&lt;h2&gt;Changed&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Using &lt;tt class="docutils literal"&gt;:download&lt;/tt&gt; now uses the page's title as filename.&lt;/li&gt;
&lt;li&gt;Using &lt;tt class="docutils literal"&gt;:back&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;:forward&lt;/tt&gt; with a count now skips intermediate pages.&lt;/li&gt;
&lt;li&gt;When there are multiple messages shown, the timeout is increased.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:search&lt;/tt&gt; now only clears the search if one was displayed before, so pressing
&lt;tt class="docutils literal"&gt;&amp;lt;Escape&amp;gt;&lt;/tt&gt; doesn't un-focus inputs anymore.&lt;/li&gt;
&lt;li&gt;Pinned tabs now adjust to their text's width, so the &lt;tt class="docutils literal"&gt;tabs.width.pinned&lt;/tt&gt;
setting got removed.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:set-cmd-text&lt;/span&gt;&lt;/tt&gt; now has a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--run-on-count&lt;/span&gt;&lt;/tt&gt; argument to run the underlying
command directly if a count was given.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:scroll-perc&lt;/span&gt;&lt;/tt&gt; got renamed to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:scroll-to-perc&lt;/span&gt;&lt;/tt&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="removed"&gt;
&lt;h2&gt;Removed&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Migrating QtWebEngine data written by versions before 2016-11-15 (before
v0.9.0) is now not supported anymore.&lt;/li&gt;
&lt;li&gt;Upgrading qutebrowser with a version older than v0.4.0 still running now won't
work properly anymore.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--harfbuzz&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--relaxed-config&lt;/span&gt;&lt;/tt&gt; commandline arguments got dropped.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="fixes"&gt;
&lt;h2&gt;Fixes&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Exiting fullscreen via &lt;tt class="docutils literal"&gt;:fullscreen&lt;/tt&gt; or buttons on a page now
restores the correct previous window state (maximized/fullscreen).&lt;/li&gt;
&lt;li&gt;When &lt;tt class="docutils literal"&gt;input.insert_mode.auto_load&lt;/tt&gt; is set, background tabs now don't enter
insert mode anymore.&lt;/li&gt;
&lt;li&gt;The keybinding help widget now works correctly when using keybindings with a
count.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;window.hide_wayland_decoration&lt;/tt&gt; setting now works correctly again.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>qutebrowser v1.0.0 is coming closer</title><link href="https://blog.qutebrowser.org/qutebrowser-v100-is-coming-closer.html" rel="alternate"></link><published>2017-09-28T21:12:21+02:00</published><updated>2017-09-28T21:12:21+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2017-09-28:/qutebrowser-v100-is-coming-closer.html</id><summary type="html">&lt;p&gt;just a quick update to let you know that the last one of four big changes is
now done:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;[x] The new completion, based on sqlite&lt;/li&gt;
&lt;li&gt;[x] The new config system&lt;/li&gt;
&lt;li&gt;[x] Dropping legacy support&lt;/li&gt;
&lt;li&gt;[x] &lt;strong&gt;Making QtWebEngine the default backend&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If QtWebEngine can't be used on your system for …&lt;/p&gt;</summary><content type="html">&lt;p&gt;just a quick update to let you know that the last one of four big changes is
now done:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;[x] The new completion, based on sqlite&lt;/li&gt;
&lt;li&gt;[x] The new config system&lt;/li&gt;
&lt;li&gt;[x] Dropping legacy support&lt;/li&gt;
&lt;li&gt;[x] &lt;strong&gt;Making QtWebEngine the default backend&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If QtWebEngine can't be used on your system for some reason, you'll get a
message about it. If it can, it'll automatically use that unless you set the
&amp;quot;backend&amp;quot; setting to &amp;quot;webkit&amp;quot;.&lt;/p&gt;
&lt;p&gt;I still hope to get v1.0.0 with all this out in mid-November, before
Firefox 57 is released - if possible, with some initial form of per-domain
settings!&lt;/p&gt;
&lt;p&gt;If you find any issues or need help, please let me know!&lt;/p&gt;
</content></entry><entry><title>New config merged!</title><link href="https://blog.qutebrowser.org/new-config-merged.html" rel="alternate"></link><published>2017-09-23T19:15:11+02:00</published><updated>2017-09-23T19:15:11+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2017-09-23:/new-config-merged.html</id><summary type="html">&lt;p&gt;It's been a long time since the last post here - a new update is way overdue,
especially seeing that the new config was merged a week ago!&lt;/p&gt;
&lt;p&gt;Apologies for the delay! After my exams and holidays were finished, I worked for
another two days full-time (plus some more) last week …&lt;/p&gt;</summary><content type="html">&lt;p&gt;It's been a long time since the last post here - a new update is way overdue,
especially seeing that the new config was merged a week ago!&lt;/p&gt;
&lt;p&gt;Apologies for the delay! After my exams and holidays were finished, I worked for
another two days full-time (plus some more) last week. Shortly after that I
wanted to write this blog post, but I was busy talking to people about their
issues with the new config, fixing a lot of little bugs, and opening issues for
everything which might take a bit longer.&lt;/p&gt;
&lt;p&gt;For everyone wondering about my exams: They went great! It was quite annoying
that I had to pause working on qutebrowser before the new config was merged to
focus on learning, but it definitely was the right decision.&lt;/p&gt;
&lt;div class="section" id="end-of-the-crowdfunding"&gt;
&lt;h2&gt;End of the crowdfunding&lt;/h2&gt;
&lt;p&gt;Unfortunately, this also means the crowdfunded time of working full-time on
qutebrowser is finished (at least for this year!). As usual, I'll work as much
as my time permits in my free time on it, though!&lt;/p&gt;
&lt;p&gt;Also, I still haven't had the time to take care of t-shirts yet. This is
something I plan to look at mainly at weekends, to coordinate with my girlfriend
who'll recieve the package (as she's in Austria which is in the EU, and I'm
planning to ship them from Germany again. Turns out getting things over the
border from Austria to Germany is much easier than Switzerland to Germany).&lt;/p&gt;
&lt;p&gt;Back to the good news: I've mentioned it above briefly, the new config is
finally merged! Some more details about what that means and what has happened
since the last blogpost will follow.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-big-merge"&gt;
&lt;h2&gt;The big merge&lt;/h2&gt;
&lt;p&gt;I wanted to merge the branch as fast as possible (as pull requests against the
master branch started to pile up), but there were still some things I wanted to
do before shipping out the new config to everyone:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Fixing some bugs which caused the testsuite to fail on the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;new-config&lt;/span&gt;&lt;/tt&gt; branch.&lt;/li&gt;
&lt;li&gt;Merging the newest &lt;tt class="docutils literal"&gt;master&lt;/tt&gt; with the new completion code into &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;new-config&lt;/span&gt;&lt;/tt&gt;
and resolving a lot of conflicts (thanks to Ryan Roden-Corrent / &lt;a class="reference external" href="https://github.com/rcorre"&gt;&amp;#64;rcorre&lt;/a&gt;
who did a lot of work on this!)&lt;/li&gt;
&lt;li&gt;Various changes to the module getting filesystem locations (such as the config
dir) in order to move data to more correct locations on macOS and Windows.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/1fc9817cd43fbebce7592f9bd4993c31e34f839f"&gt;Removing support&lt;/a&gt; for ambiguous keybindings shadowing each other, and the
related &lt;tt class="docutils literal"&gt;input.ambiguous_timeout&lt;/tt&gt; setting which mostly confused people.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/cee51df4fbdfcb7a974a4285e6a3764e070bf300"&gt;Changing&lt;/a&gt; the JavaScript log level setting (&lt;tt class="docutils literal"&gt;javascript.log&lt;/tt&gt;) to be able
to map JS loglevels to different qutebrowser loglevels on QtWebEngine.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/cb806aefa3b1a367fb6e79332504466a9e07781f"&gt;Implementing&lt;/a&gt; support for a &lt;tt class="docutils literal"&gt;config.py&lt;/tt&gt; file for manual configuration for advanced users.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/b8fb88f4c27b348ec129cef0638d47f833567a4e"&gt;Improving&lt;/a&gt; error handling so all errors happening in &lt;tt class="docutils literal"&gt;config.py&lt;/tt&gt; get
caught properly and displayed combined if possible.&lt;/li&gt;
&lt;li&gt;Changing the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/7c39600508004c5cb0bbde84f973209e61fec6f9"&gt;default behavior&lt;/a&gt; for Up/Down in command mode to go through the
command history, which hopefully makes that more discoverable.&lt;/li&gt;
&lt;li&gt;Adding a &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/54c417391dbe4544eed7ecfa51aa87292826b10a"&gt;configdiff&lt;/a&gt; page which shows changes in the old config compared to
the default, to make it easier to migrate. This was surprisingly easy thanks
to Python's &lt;a class="reference external" href="https://docs.python.org/3/library/difflib.html"&gt;difflib&lt;/a&gt; module.&lt;/li&gt;
&lt;li&gt;Adding a &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/blob/master/doc/help/configuring.asciidoc"&gt;documentation page&lt;/a&gt; for how to configure qutebrowser with the new config.&lt;/li&gt;
&lt;li&gt;Fixing a bug related to &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/3179e8c7b9c290bff2683efb6e0564a0301f648f"&gt;escaping&lt;/a&gt; HTML in various prompts, which became visible with the config errors.&lt;/li&gt;
&lt;li&gt;Many little bugfixes and improvements.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here's how things looked like right before the merge:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;226 files changed, 13144 insertions(+), 14030 deletions(-)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then on September 16th, I finally merged in all those changes as it was ready to
roll out to a bigger amount of people. The feedback I've gotten since then was
quite positive, but there was still a lot to do after the merge!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="after-the-merge"&gt;
&lt;h2&gt;After the merge&lt;/h2&gt;
&lt;p&gt;With the new config finally merged, I started some additional work and of course
acted upon the feedback I got from users.&lt;/p&gt;
&lt;p&gt;The first thing I did was adjusting a lot of code to make it possible to
initialize the config very early, before Qt's &lt;tt class="docutils literal"&gt;QApplication&lt;/tt&gt; object exists.
This makes it possible to configure things like the backend to use, or what
commandline arguments to pass to QtWebEngine/Chromium. There was a bit of work
involved as Qt's functions for getting e.g. the user's config dir appends the
application name, but Qt doesn't know about that before the &lt;tt class="docutils literal"&gt;QApplication&lt;/tt&gt;
exists. To make this work, qutebrowser now appends the directory if it isn't
there yet, and &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/blob/b8389e4496028fce178031fc79eee478f4d8e4c9/tests/unit/utils/test_standarddir.py#L522-L549"&gt;has a test&lt;/a&gt; ensuring that those locations match the one Qt
would return with a QApplication. With that change, support for &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/a1fa40f0679a0a365a0e33ca3a235b78f311a923"&gt;migrating
data&lt;/a&gt; written by QtWebEngine before qutebrowser v0.9.0 was also dropped, in the
hope that nobody uses it anymore.&lt;/p&gt;
&lt;p&gt;With that done, I was finally able to add a &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/fe05947b54be138ef261da00eda01474fc690345"&gt;qt_args&lt;/a&gt; and &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/b1b6c462c1a8a30abf37c4d785e5cc9925385b31"&gt;backend&lt;/a&gt; setting,
hopefully making qutebrowser wrapper scripts unnecessary!&lt;/p&gt;
&lt;p&gt;Also, I decided it was finally time to drop support for old Qt/Python/QtWebKit
versions, like &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/2742"&gt;announced&lt;/a&gt; some while ago. This meant I could delete almost
1000 lines of code dealing with those old versions (and make other code more
readable) - and to my surprise, nobody has complained yet!&lt;/p&gt;
&lt;p&gt;That change drops support for &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/505321c336408073655e33dd43f90dd327521351"&gt;Python 3.4&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/852baaa8c30b84b0870b235ff69b2d376ba0613f"&gt;Qt &amp;lt; 5.7.1&lt;/a&gt; and &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/3772dc5930e55416ac1eef0ec7a1f612bdf7d617"&gt;legacy
QtWebKit&lt;/a&gt; (but not the &lt;a class="reference external" href="https://github.com/annulen/webkit/wiki"&gt;updated fork&lt;/a&gt;). This mainly affects Ubuntu Trusty /
Debian Jessie (where you need to get a newer Python from somewhere and install
the rest &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/blob/master/doc/install.asciidoc#installing-qutebrowser-with-tox"&gt;manually&lt;/a&gt;) and Gentoo (where you need to install a Python 3.5/3.6
from &amp;quot;unstable&amp;quot; and a newer QtWebKit or QtWebEngine).&lt;/p&gt;
&lt;p&gt;I also &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/3a5241b642da666e4517a32e0eb945254d86a6da"&gt;introduced&lt;/a&gt; the &lt;a class="reference external" href="http://www.attrs.org/"&gt;attrs&lt;/a&gt; library as a new dependency, making writing
&amp;quot;data classes&amp;quot; in Python much more easier. A lot of projects started using it
recently, as it definitely helps cutting down a lot of boilerplate code (to the
point that it's &lt;a class="reference external" href="https://www.python.org/dev/peps/pep-0557/"&gt;discussed&lt;/a&gt; whether Python should add a similar feature to its
standard library).&lt;/p&gt;
&lt;p&gt;Then I started reviewing crash reports and pull requests I've been ignoring
because of my exams, as well as fixing lots of small bugs with the new config
(which is still &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues?q=is%3Aissue+is%3Aopen+label%3A%22component%3A+config%22"&gt;ongoing&lt;/a&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="other-work"&gt;
&lt;h2&gt;Other work&lt;/h2&gt;
&lt;p&gt;A quick overview about other things which have happened since the last post on
July 7th:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/pull/2295"&gt;new completion&lt;/a&gt; was merged! &lt;a class="reference external" href="https://github.com/rcorre"&gt;&amp;#64;rcorre&lt;/a&gt; has been working on this for over
a year, so we're both glad it was finally finished and merged. This means big
speed improvements especially for the &lt;tt class="docutils literal"&gt;:open&lt;/tt&gt; completion, and easier writing
of new completions inside qutebrowser.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:download&lt;/tt&gt; now &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/pull/2753"&gt;uses the page title&lt;/a&gt; as filename in some cases.&lt;/li&gt;
&lt;li&gt;The status bar gained a new &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/pull/2738"&gt;back/forward indicator&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Messages are now &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/pull/2808"&gt;shown longer&lt;/a&gt; if there are many of them.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;PyOpenGL&lt;/tt&gt; dependency was dropped by &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/a942613d7fea62932de3ced4008ebbb8ae190bc4"&gt;using a simpler workaround&lt;/a&gt; for
OpenGL issues with QtWebEngine.&lt;/li&gt;
&lt;li&gt;Lots of other smaller work!&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="moving-on"&gt;
&lt;h2&gt;Moving on&lt;/h2&gt;
&lt;p&gt;My studies started again last week, so things are going to be a bit slower again
going forward.&lt;/p&gt;
&lt;p&gt;After the current smaller issues with the new config are fixed, the next things
I want to take care of are what's missing to finally make QtWebEngine the
default backend everywhere.&lt;/p&gt;
&lt;p&gt;Once that's done, the last important missing bit is per-domain settings. Those
will still be some work, but now that the new config is in, it'll be much easier
to make it happen.&lt;/p&gt;
&lt;p&gt;I'd really like to release v1.0.0 before November 14th, when Firefox 57 will be
released (dropping support for legacy addons, and thus
&lt;a class="reference external" href="http://vimperator.org/vimperator.html"&gt;Vimperator&lt;/a&gt; and &lt;a class="reference external" href="http://5digits.org/pentadactyl/"&gt;Pentadactyl&lt;/a&gt;). I think per-domain settings are a feature
which definitely should be in v1.0.0, so I'll try my best to make it happen
until then.&lt;/p&gt;
&lt;/div&gt;
</content></entry><entry><title>Config revolution - Part 1 finished</title><link href="https://blog.qutebrowser.org/config-revolution-part-1-finished.html" rel="alternate"></link><published>2017-07-07T16:18:28+02:00</published><updated>2017-07-07T16:18:28+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2017-07-07:/config-revolution-part-1-finished.html</id><summary type="html">&lt;p&gt;Since the last blogpost, I worked on the new config for another 5 days, so we're
on day 17 now (already! Gnah...).&lt;/p&gt;
&lt;p&gt;Sorry there wasn't an update in such a long time. I wanted to write a blog post
multiple times, even wrote about half of it, and then other …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Since the last blogpost, I worked on the new config for another 5 days, so we're
on day 17 now (already! Gnah...).&lt;/p&gt;
&lt;p&gt;Sorry there wasn't an update in such a long time. I wanted to write a blog post
multiple times, even wrote about half of it, and then other stuff got in the
way. I guess it shows that I prefer coding to blogging... :D&lt;/p&gt;
&lt;p&gt;My eye surgery &lt;a class="reference external" href="https://www.reddit.com/r/Strabismus/comments/6jkqla/achievement_unlocked_stereo_vision/"&gt;went quite well&lt;/a&gt;, and I was able to start working again last
week.&lt;/p&gt;
&lt;p&gt;This is how things look:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;218 files changed, 10234 insertions(+), 13768 deletions(-)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is definitely the biggest change in qutebrowser's history... QtWebEngine
was something like ~2500 new lines (and ~900 deleted) when I was able to merge
the branch back in, but here it's all or nothing, because I only want one big
config breakage for users using the git repo.&lt;/p&gt;
&lt;p&gt;All tests are passing on the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;new-config&lt;/span&gt;&lt;/tt&gt; branch by now:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;4888 passed, 170 skipped, 60 xfailed in 605.11 seconds&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This means the first phase of the config refactoring is complete. Everything is
using the new config (with the exception of the setting completion, which is
postponed until the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/pull/2295"&gt;new completion code&lt;/a&gt; is in), and everything is cleaned up.&lt;/p&gt;
&lt;p&gt;I originally wanted to spend less time on this and postpone tests and such to
after the crowdfunded time (and instead focus on the Python config and
per-domain settings), but I decided it'd be better to finish what I started
first. Otherwise, with such big changes, this would create a lot of trouble down
the line.&lt;/p&gt;
&lt;p&gt;If you want to try the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;new-config&lt;/span&gt;&lt;/tt&gt; branch, it's definitely ready to see some
testing, and I'd appreciate feedback! There is no &lt;tt class="docutils literal"&gt;config.py&lt;/tt&gt; file yet, but if
you're the kind of person who prefers &lt;tt class="docutils literal"&gt;:set&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;qute://settings&lt;/span&gt;&lt;/tt&gt;, it should
be good to go! Note that on Windows and macOS there will be breaking changes to
the config's location, though - see the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/projects/2"&gt;project board&lt;/a&gt; on GitHub to see what's
still missing.&lt;/p&gt;
&lt;p&gt;With that done, I will now take a longer break from qutebrowser work and focus
on my upcoming exams instead. I'll be back for the remaining 3 days (and maybe a
bit more full-time work on top, time permitting) in September, after my exams
are done.&lt;/p&gt;
&lt;p&gt;The T-shirts will also be postponed until then - like shown on the &lt;a class="reference external" href="https://www.kickstarter.com/projects/the-compiler/qutebrowser-v10-with-per-domain-settings"&gt;Kickstarter
page&lt;/a&gt;, it's going to be somewhen between September to December until they are
sent.&lt;/p&gt;
&lt;p&gt;See the next few sections on what happened in the past few days, though!&lt;/p&gt;
&lt;div class="section" id="keybindings"&gt;
&lt;h2&gt;Keybindings&lt;/h2&gt;
&lt;p&gt;Like I mentioned in the &lt;a class="reference external" href="https://blog.qutebrowser.org/refactoring-more-things-a-working-yaml-config-and-more.html"&gt;last update&lt;/a&gt;, my previous solution for handling
keybindings wasn't really usable. Originally, all the default bindings were
stored in the config like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;bindings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;normal&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;gg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;scroll-perc 0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When adding a new binding, the config would (correctly) detect that
&lt;tt class="docutils literal"&gt;bindings.commands&lt;/tt&gt; was changed, and then add the complete new value
(including all default bindings) in your &lt;tt class="docutils literal"&gt;autoconfig.yml&lt;/tt&gt;. This clearly wasn't
the way to go.&lt;/p&gt;
&lt;p&gt;I found a straightforward solution though: There are now two settings,
&lt;tt class="docutils literal"&gt;bindings.default&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;bindings.commands&lt;/tt&gt; (empty by default, i.e. &lt;tt class="docutils literal"&gt;{}&lt;/tt&gt;)
in the config. For keybindings, both are merged, starting with the default one.&lt;/p&gt;
&lt;p&gt;This has various benefits:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;When you want to add a new binding, you only mutate &lt;tt class="docutils literal"&gt;bindings.commands&lt;/tt&gt;, so
you only get your custom bindings in your config file.&lt;/li&gt;
&lt;li&gt;When you don't want to load any default binding at all, you set
&lt;tt class="docutils literal"&gt;bindings.default = {}&lt;/tt&gt; - then only your custom bindings are bound.&lt;/li&gt;
&lt;li&gt;When you want the default bindings, but don't want any new defaults
automatically, you pin &lt;tt class="docutils literal"&gt;bindings.default&lt;/tt&gt; to its default value
explicitly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think this is a great solution - it's straightforward, and it makes things
very flexible.&lt;/p&gt;
&lt;p&gt;With that in place, I also updated all the code using those keybindings, and
simplified some of it. That means &lt;tt class="docutils literal"&gt;:bind&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;:unbind&lt;/tt&gt; now work like you'd
expect again (and modify &lt;tt class="docutils literal"&gt;bindings.commands&lt;/tt&gt;).&lt;/p&gt;
&lt;p&gt;I also added a &lt;tt class="docutils literal"&gt;bindings.key_mappings&lt;/tt&gt; which can be used to transparently map
a key to another one. For example, by default &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;&amp;lt;Ctrl-[&amp;gt;&lt;/span&gt;&lt;/tt&gt; is mapped to
&lt;tt class="docutils literal"&gt;&amp;lt;Escape&amp;gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;&amp;lt;Ctrl-J&amp;gt;&lt;/span&gt;&lt;/tt&gt; to &lt;tt class="docutils literal"&gt;&amp;lt;Enter&amp;gt;&lt;/tt&gt;, so for any binding which is bound
to &lt;tt class="docutils literal"&gt;&amp;lt;Enter&amp;gt;&lt;/tt&gt; you can press &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;&amp;lt;Ctrl-J&amp;gt;&lt;/span&gt;&lt;/tt&gt; instead.&lt;/p&gt;
&lt;p&gt;This is probably also very useful to adjust to different keyboard layouts, if
you want to keep the bindings in the same place without rebinding everything.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="testing"&gt;
&lt;h2&gt;Testing&lt;/h2&gt;
&lt;p&gt;To make sure the new config doesn't end up as the unmaintainable mess the old
config was, I decided pretty early on that I wanted 100% test coverage for all
new config code, just like &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/blob/new-config/scripts/dev/check_coverage.py#L42"&gt;for some other modules&lt;/a&gt; which are easy to test.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/tree/new-config/tests/unit/config"&gt;Writing the tests&lt;/a&gt; turned up some issues - among them &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/e259293f8/"&gt;an issue&lt;/a&gt; where
modifying the configuration also modified the default value stored in
qutebrowser internally... This one definitely would've been a big pain to debug
further down the road.&lt;/p&gt;
&lt;p&gt;After getting those all to pass (with 100% coverage), I also updated all older
tests for the new configuration - this &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/compare/78d7ac311f78595450519e4d754696c4bfb2cc9e...9db4a8cb43001838fbc76f849662eef82ca3bf5f"&gt;turned out to be&lt;/a&gt; much more
straightforward than I thought it would be, with only a few things requiring a
bit more work (mostly tests related to keybindings).&lt;/p&gt;
&lt;p&gt;Completion tests are still skipped though, I'll take care of those once the new
completion is merged in.&lt;/p&gt;
&lt;p&gt;After everything looked nice and green locally, I pushed them and hoped things
would look the same on Travis - however, I was in for some not-so-nice suprises with older Python versions:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Python 3.4 is &lt;a class="reference external" href="https://bugs.python.org/issue17636"&gt;worse at dealing with circular imports&lt;/a&gt; than 3.5 is, so I
had to &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/91cd6c6288dae389818cc40de0d223cd9a16363d"&gt;move some imports&lt;/a&gt; to accomodate for that. I really hope I'll be
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/2742"&gt;able to drop&lt;/a&gt; Python 3.4 for v1.0, though!&lt;/li&gt;
&lt;li&gt;In Python 3.6, dictionaries are &lt;a class="reference external" href="https://docs.python.org/3/whatsnew/3.6.html#whatsnew36-compactdict"&gt;ordered by default&lt;/a&gt; (as an implementation
detail), which caused me to not &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/0528a800f264a52b7dfdbff21c5d2b64a9001ad2"&gt;catch some issues&lt;/a&gt; where the tests relayed
on that property.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then there were some bigger issues...&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="unicode-is-hard"&gt;
&lt;h2&gt;Unicode is hard!&lt;/h2&gt;
&lt;p&gt;A test using &lt;a class="reference external" href="http://hypothesis.works/"&gt;hypothesis&lt;/a&gt; to do some intelligent fuzzing showed an issue I haven't seen locally, and was quite interesting.
A slightly simplified version of the test:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nd"&gt;@hypothesis.given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;strategies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dictionaries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;strategies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;booleans&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_hypothesis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;configtypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keytype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;configtypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                         &lt;span class="n"&gt;valtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;configtypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                         &lt;span class="n"&gt;none_ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;converted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_py&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converted&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;converted&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;converted&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;configexc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Invalid unicode in the string, etc...&lt;/span&gt;
        &lt;span class="n"&gt;hypothesis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It uses Hypothesis to get dictionaries which are filled with random data like
&lt;tt class="docutils literal"&gt;{'x': True}&lt;/tt&gt;, converts them to a string (like qutebrowser would when e.g.
showing the value in the completion), converts that value back to Python again
(like qutebrowser would when using &lt;tt class="docutils literal"&gt;:set&lt;/tt&gt;) and makes sure the same thing comes
out.&lt;/p&gt;
&lt;p&gt;The problem here was that qutebrowser uses &lt;a class="reference external" href="https://en.wikipedia.org/wiki/JSON"&gt;JSON&lt;/a&gt; to convert lists/dicts in the
new config to a string (because it outputs compact, one-line representations),
but &lt;a class="reference external" href="https://en.wikipedia.org/wiki/YAML"&gt;YAML&lt;/a&gt; to parse lists/dicts from a string (because it allows for more a
more lightweight syntax like &lt;tt class="docutils literal"&gt;{Hello: World}&lt;/tt&gt; instead of
&lt;tt class="docutils literal"&gt;{&amp;quot;Hello&amp;quot;: &amp;quot;World&amp;quot;}&lt;/tt&gt;).&lt;/p&gt;
&lt;p&gt;This shouldn't be a problem because YAML is &lt;a class="reference external" href="https://en.wikipedia.org/wiki/YAML#Comparison_with_JSON"&gt;supposed to be&lt;/a&gt; a superset of
JSON - however, turned out that's not true. Unicode codepoints starting from
U+10000 are encoded as a &lt;a class="reference external" href="https://en.wikipedia.org/wiki/UTF-16#U.2B10000_to_U.2B10FFFF"&gt;surrogate&lt;/a&gt; in UTF-16. Since JavaScript (until
recently) didn't have escapes for those 4-byte characters, JSON &lt;a class="reference external" href="https://stackoverflow.com/questions/38463038/why-does-json-encode-utf-16-surrogate-pairs-instead-of-unicode-code-points-direc/38552626#38552626"&gt;encodes them&lt;/a&gt;
to a UTF-16 surrogate, which then gets read incorrectly by YAML:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\U00010000&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\ud800\udc00&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &amp;quot;solution&amp;quot; for this was easy: Simply &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/9ac2dbcc80330c6090ecdce656046931e8cf591b"&gt;disallowing&lt;/a&gt; those characters in the
config inside dicts and lists.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="configdata-yml-performance"&gt;
&lt;h2&gt;configdata.yml performance&lt;/h2&gt;
&lt;p&gt;With the new configuration, all available config options are &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/blob/new-config/qutebrowser/config/configdata.yml"&gt;defined&lt;/a&gt; in a
YAML file (instead of an &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/blob/v0.11.0/qutebrowser/config/configdata.py#L133"&gt;almost uneditable&lt;/a&gt; Python file like before), see my
older blog posts for details.&lt;/p&gt;
&lt;p&gt;On every start, qutebrowser reads that config file and generates an internal
structure with all available settings and default values. Now for some reason,
this takes around 20 seconds (!) on Travis CI, for a ~2200 line YAML file. I've
heard about YAML being a bit slow sometimes, but certainly didn't expect this.&lt;/p&gt;
&lt;p&gt;I did some tests locally, and checked what difference the C extension of PyYAML
makes (it has both an accelerated C implementation with a thin Python layer, and
a pure-Python implementation).&lt;/p&gt;
&lt;p&gt;With the C extension, reading the file took around 20ms on my machine, which is
entirely reasonable. With it disabled, this jumped to 200ms which already isn't
as nice anymore, but still bearable. But still, this is all orders of magnitude
off from 20 seconds.&lt;/p&gt;
&lt;p&gt;I still have no idea what happened there - I decided to &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/2777"&gt;open an issue&lt;/a&gt; (with
some ideas like &amp;quot;compiling&amp;quot; the YAML to a Python file), and move on for now
(after skipping the benchmark I wrote on Travis, because it took way too long).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="documentation-generation"&gt;
&lt;h2&gt;Documentation generation&lt;/h2&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/blob/new-config/doc/help/settings.asciidoc"&gt;settings reference&lt;/a&gt; in qutebrowser's documentation is autogenerated (but
stored in the repository), with Travis making sure it doesn't end up being stale.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/25ab3b30c2f3a49932d6d5d1a382dfeed5907b0c#diff-08e76fb7836503b745e1d25e63f4f413"&gt;Updating&lt;/a&gt; the script to generate docs for the new config was relatively easy
(especially because every config type already had a &lt;tt class="docutils literal"&gt;.to_str()&lt;/tt&gt; implemented),
but Travis told me that it still detected uncommited changes in the docs.&lt;/p&gt;
&lt;p&gt;After &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/f92ccd48936882fbbf069b518769a7d0f07cbc66"&gt;changing the script&lt;/a&gt; which checks for those to show a &lt;tt class="docutils literal"&gt;git diff&lt;/tt&gt; when
it fails, it was clear what was happening: It was dictionaries being ordered
differently again. A value like &lt;tt class="docutils literal"&gt;{&amp;quot;one&amp;quot;: 1, &amp;quot;two&amp;quot;: 2}&lt;/tt&gt; could be shown as
either that, or &lt;tt class="docutils literal"&gt;{&amp;quot;two&amp;quot;: 2, &amp;quot;one&amp;quot;: 1}&lt;/tt&gt; in the docs.&lt;/p&gt;
&lt;p&gt;I ended up doing something I wanted to postpone until some later point: Showing
dictionaries and lists nicely as lists in the documentation, by
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/88b878098da5cb410766ad22ba51f068f0cf1dd4"&gt;pretty-printing&lt;/a&gt; them with a &lt;tt class="docutils literal"&gt;.to_doc()&lt;/tt&gt; method (which would just fall back
to &lt;tt class="docutils literal"&gt;.to_str()&lt;/tt&gt; for most types).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="new-release"&gt;
&lt;h2&gt;New release&lt;/h2&gt;
&lt;p&gt;This week, PyQt 5.9 was finally &lt;a class="reference external" href="https://www.riverbankcomputing.com/pipermail/pyqt/2017-July/039378.html"&gt;released&lt;/a&gt;. It ships with Qt 5.9, which comes
with some &lt;a class="reference external" href="http://code.qt.io/cgit/qt/qtwebengine.git/tree/dist/changes-5.9.0?h=v5.9.1#n19"&gt;long-awaited&lt;/a&gt; QtWebEngine fixes.&lt;/p&gt;
&lt;p&gt;This means it was finally time to &lt;a class="reference external" href="https://lists.schokokeks.org/pipermail/qutebrowser-announce/2017-July/000019.html"&gt;release&lt;/a&gt; qutebrowser v0.11, with lots of
bugfixes and new features (like the new private browsing supporting QtWebEngine,
or pinned tabs).&lt;/p&gt;
&lt;p&gt;A lot of the release process is automated already, but unfortunately, things
didn't go quite as planned at first...&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;First, GitHub's API just showed me a &amp;quot;Broken pipe&amp;quot; error when trying to upload
the source release. After some while I figured out that the files were kind-of
half uploaded, and after removing them again manually, it worked.&lt;/li&gt;
&lt;li&gt;My Windows VM constantly used 100% CPU and refused to tell me why - and was
unusable as a result of that, with some 10s delay for every keypress. A reboot
didn't help, but a hard reset did.&lt;/li&gt;
&lt;li&gt;On Windows, I accidentally ran the release script in a &lt;a class="reference external" href="https://virtualenv.pypa.io/"&gt;virtualenv&lt;/a&gt; without
the &lt;a class="reference external" href="http://github3py.readthedocs.io/en/master/"&gt;github3&lt;/a&gt; package installed - however, the script only failed after some
10-15 minutes after the package was built. It now &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/5098aa388b9802c5279322f2500ec19da439bc20"&gt;checks for that&lt;/a&gt; earlier.&lt;/li&gt;
&lt;li&gt;Running qutebrowser from the binary failed because &lt;a class="reference external" href="http://www.pyinstaller.org/"&gt;PyInstaller&lt;/a&gt; didn't know
about some hidden PyQt OpenGL module - so I &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/2df9508e44cd6839075c7be725fb13ced4563a08"&gt;told it&lt;/a&gt; about it.&lt;/li&gt;
&lt;li&gt;On macOS, the QtWebEngine resource files &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/8f03a36862bdb0d288937de7ced3785c4d62df52"&gt;weren't copied correctly&lt;/a&gt;.
I'm not sure why the last release even worked properly...&lt;/li&gt;
&lt;li&gt;Unmounting any volumes on my Mac (&lt;tt class="docutils literal"&gt;hdiutil detach&lt;/tt&gt;) mysteriously failed
(with a &lt;tt class="docutils literal"&gt;device busy&lt;/tt&gt;). I adjusted the script to &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/725d4a44f01de99fab5d9e4404a9123f40ec8915"&gt;deal with that&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The script still used the old Windows installer names (&lt;tt class="docutils literal"&gt;.msi&lt;/tt&gt; instead of
&lt;tt class="docutils literal"&gt;.exe&lt;/tt&gt;), which I &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/eaecfe5882f59abaecabb688340c88b8638f4b1b"&gt;fixed too&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This all means this release took more than 3 hours instead of the usual half an
hour or so... but I managed to upload everything!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="completion-refactoring"&gt;
&lt;h2&gt;Completion refactoring&lt;/h2&gt;
&lt;p&gt;The other big change which is currently ongoing for v1.0 (the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/pull/2295"&gt;new completion
PR&lt;/a&gt; from &lt;tt class="docutils literal"&gt;&amp;#64;rcorre&lt;/tt&gt;) has also seen some work, with me mostly investing some
more time in reviewing changes and reviewing the entire contribution (2600 new
lines, 2700 deleted) again.&lt;/p&gt;
&lt;p&gt;After &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/pull/2295#issuecomment-313380120"&gt;some more minor things&lt;/a&gt; are taken care of, I hope to merge it into
&lt;tt class="docutils literal"&gt;master&lt;/tt&gt; (which is now for v1.0 material) soon.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="miscellaneous"&gt;
&lt;h2&gt;Miscellaneous&lt;/h2&gt;
&lt;p&gt;There was a lot of other stuff too, but this blog post would get way too long if I mentioned them all. Some examples:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;content.user_stylesheets&lt;/tt&gt; &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/4562a3574b7f887b811a93e76e0f15ac476c6359"&gt;is now a list&lt;/a&gt; taking multiple CSS files.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;content.headers.do_not_track&lt;/tt&gt; &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/5ada3606d88f5ee629fcd808f92e6bcaa9303204"&gt;now allows to&lt;/a&gt; not send the &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Do_Not_Track"&gt;DNT header&lt;/a&gt; at all.&lt;/li&gt;
&lt;li&gt;Various &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/2708#issuecomment-312450216"&gt;setting renames&lt;/a&gt; and clarifications.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, I wanted to make sure all my thoughts are written down before leaving
this alone for the next few weeks. After closing various old/stale pull
requests, I also &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues?q=is%3Aissue+is%3Aopen+label%3A%22config+revolution%22"&gt;opened&lt;/a&gt; various new issues to keep track of everything that's
still missing, and so I can close the old big &amp;quot;Config (r)evolution&amp;quot; &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/499"&gt;issue&lt;/a&gt;
which has gotten quite big (100 comments).&lt;/p&gt;
&lt;p&gt;I also made sure the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/projects/2"&gt;project board&lt;/a&gt; on GitHub for the new config is up to
date, including a column for all issues which need to be tackled before merging
this all to master... which will happen in September, after my exams.&lt;/p&gt;
&lt;/div&gt;
</content></entry><entry><title>Refactoring more things, a working YAML config, and more!</title><link href="https://blog.qutebrowser.org/refactoring-more-things-a-working-yaml-config-and-more.html" rel="alternate"></link><published>2017-06-20T21:01:28+02:00</published><updated>2017-06-20T21:01:28+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2017-06-20:/refactoring-more-things-a-working-yaml-config-and-more.html</id><summary type="html">&lt;p&gt;It's day 12 of 20, and I did a lot more work on making everything (including
tests) use the new config. I also implemented initial support for reading
from/writing to YAML files.&lt;/p&gt;
&lt;p&gt;This is how things look now:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;154 files changed, 6128 insertions(+), 7000 deletions(-)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is with all …&lt;/p&gt;</summary><content type="html">&lt;p&gt;It's day 12 of 20, and I did a lot more work on making everything (including
tests) use the new config. I also implemented initial support for reading
from/writing to YAML files.&lt;/p&gt;
&lt;p&gt;This is how things look now:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;154 files changed, 6128 insertions(+), 7000 deletions(-)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is with all end2end tests also adjusted for the new config. I haven't
looked at the unit tests yet, but things are getting better!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;1001 passed, 42 skipped, 10 xfailed in 374.00 seconds&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I was also finally able to &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/26753bfb4ff8c1d0bcff494ece734804f16afc2f"&gt;remove&lt;/a&gt; almost all the legacy config code, so it's
only the new code around now.&lt;/p&gt;
&lt;p&gt;Setting values and saving/restoring them already works, with either &lt;tt class="docutils literal"&gt;:set&lt;/tt&gt; or
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;qute://settings&lt;/span&gt;&lt;/tt&gt;. As I already was working on &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;qute://settings&lt;/span&gt;&lt;/tt&gt;, I also
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/15e803c02af52d99f11db9b6233a1fdfd4312d0d"&gt;made it work&lt;/a&gt; with QtWebEngine, which was something which was requested a lot.&lt;/p&gt;
&lt;div class="section" id="config-types"&gt;
&lt;h2&gt;config types&lt;/h2&gt;
&lt;p&gt;There's a &lt;tt class="docutils literal"&gt;configtypes.py&lt;/tt&gt; module in qutebrowser which defines all the
different types (such as a string, or a list of regexes) in the configuration.&lt;/p&gt;
&lt;p&gt;A setting type also can convert a value (of its type) to either a string (for
&lt;cite&gt;:set&lt;/cite&gt;), or to whatever the Python code using the config expects (such as a
Python list of compiled regex patterns).&lt;/p&gt;
&lt;p&gt;When implementing the new config, I first thought that with the new config, the
value which will be stored internally would be the converted Python value.&lt;/p&gt;
&lt;p&gt;Originally, a type was looking like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;from_py&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Convert the value from a config.py or YAML file to a&lt;/span&gt;
        &lt;span class="c1"&gt;# value used by the rest of the code (and stored as&lt;/span&gt;
        &lt;span class="c1"&gt;# internally).&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Convert the value from plaintext to a value used like&lt;/span&gt;
        &lt;span class="c1"&gt;# explained above.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, I found out that that's actually a problem - for some kind of values
(like a &lt;tt class="docutils literal"&gt;QColor&lt;/tt&gt; object, or a proxy object), they can't be converted back to a
string losslessly.&lt;/p&gt;
&lt;p&gt;The API also was quite confusing - a lost a bit of time because I once assumed
&lt;tt class="docutils literal"&gt;from_py&lt;/tt&gt; would be what gets the value from qutebrowser's code.&lt;/p&gt;
&lt;p&gt;I ended up instead storing the value as it's saved in &lt;tt class="docutils literal"&gt;config.py&lt;/tt&gt; or the YAML
file, so as a string/list/dict/bool/int/float.&lt;/p&gt;
&lt;p&gt;Then, a type looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Convert the value from plaintext to a YAML-like value.&lt;/span&gt;
        &lt;span class="c1"&gt;# (which is also what&amp;#39;s stored internally)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;from_py&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Convert the value from how it&amp;#39;s stored internally&lt;/span&gt;
        &lt;span class="c1"&gt;# to what is used by the rest of the code.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This worked out pretty well, and made it easy to implement &lt;tt class="docutils literal"&gt;:set&lt;/tt&gt; and reading
from YAML.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="mutables"&gt;
&lt;h2&gt;Mutables&lt;/h2&gt;
&lt;p&gt;Another big issue I was facing is how to deal with mutables. If a &lt;tt class="docutils literal"&gt;config.py&lt;/tt&gt;
would do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;custom_headers&lt;/span&gt;
&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;X-Foo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;the config wouldn't get updated, and that's probably quite
unexpected.&lt;/p&gt;
&lt;p&gt;First I tried solving that by returning custom list/dict objects from the
config, which notifies the config when they've been mutated:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConfigNotifierMixin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_inited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_option&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_origin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_inited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__getitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__getitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrap_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_manager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_option&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_origin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__setitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wrap_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_manager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_option&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_origin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__setitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_inited&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_option&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_origin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__delitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__delitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_inited&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_option&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_origin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConfigDict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ConfigNotifierMixin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserDict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConfigList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ConfigNotifierMixin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserList&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrap_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConfigList&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ConfigList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConfigDict&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ConfigDict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But I wasn't been able to make that work properly. Either some sub-values
weren't wrapped properly, or I got some funny infinite recursion in Jinja (the
templating engine qutebrowser uses).&lt;/p&gt;
&lt;p&gt;In the end, I went for a &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/6e4a5319cee60278106b51c57e30f639a1051449"&gt;simpler solution&lt;/a&gt; - for every value qutebrowser
returns, it saves a reference to it as well as a (deep) copy of it. Then, after
e.g. a &lt;tt class="docutils literal"&gt;config.py&lt;/tt&gt; has been executed, it checks the saved values for changes,
and calls &lt;tt class="docutils literal"&gt;config.set&lt;/tt&gt; as appropriate.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="yaml-saving-restoring"&gt;
&lt;h2&gt;YAML saving/restoring&lt;/h2&gt;
&lt;p&gt;With all the converting already done in &lt;tt class="docutils literal"&gt;configtypes&lt;/tt&gt;, implementing this was
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/6375530bfad5daee5789d3308851e809e491ae5c"&gt;a breeze&lt;/a&gt;. Now whatever has been changed via &lt;tt class="docutils literal"&gt;:set&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;qute://settings&lt;/span&gt;&lt;/tt&gt;
is saved to a YAML file (and loaded from there), and it was really easy to
implement that. The new config code being much cleaner and more modular already
payed off, even when it was a long way there!&lt;/p&gt;
&lt;p&gt;As an example, when doing &lt;tt class="docutils literal"&gt;:set tabs.position left&lt;/tt&gt; and quitting, this ends up
in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;~/.config/qutebrowser/autoconfig.yml&lt;/span&gt;&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# DO NOT edit this file by hand, qutebrowser will overwrite it.&lt;/span&gt;
&lt;span class="c1"&gt;# Instead, create a config.py - see :help for details.&lt;/span&gt;

&lt;span class="l l-Scalar l-Scalar-Plain"&gt;global&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l l-Scalar l-Scalar-Plain"&gt;tabs.position&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;left&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="keybindings"&gt;
&lt;h2&gt;Keybindings&lt;/h2&gt;
&lt;p&gt;Currently, the bindings are just something like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;bindings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;normal&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;gg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;scroll-perc 0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;in the config - i.e., just a value like any other, set to a dict of dicts.&lt;/p&gt;
&lt;p&gt;However, that turned out to not be very practical - if a single binding is
changed, the whole &lt;tt class="docutils literal"&gt;bindings.commands&lt;/tt&gt; value is treated as modified, and thus
saved in the config.&lt;/p&gt;
&lt;p&gt;This definitely needs some re-thinking and probably some special-casing.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="sql-completion"&gt;
&lt;h2&gt;SQL completion&lt;/h2&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/pull/2295"&gt;pull request&lt;/a&gt; for the new sqlite completion (and related completion
refactoring) also has seen some progress (mostly thanks to &lt;tt class="docutils literal"&gt;&amp;#64;rcorre&lt;/tt&gt;).&lt;/p&gt;
&lt;p&gt;Today, I also fixed a data corruption issue which showed up in the SQL branch
since somewhen recently - turned out it was &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/29ce1b381121645589cb18906682fe79b11a69b8"&gt;an issue&lt;/a&gt; with how SQL columns
were inserted into the database, which caused things to get mixed up.&lt;/p&gt;
&lt;p&gt;I also decided to give &lt;a class="reference external" href="https://reviewable.io/"&gt;reviewable.io&lt;/a&gt; another try, as reviewing stuff of this
size is really cumbersome with GitHub... I did an &lt;a class="reference external" href="https://reviewable.io/reviews/qutebrowser/qutebrowser/2295"&gt;initial review&lt;/a&gt; there, and
now I'm wondering whether that'll work out better.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="dropping-legacy-support"&gt;
&lt;h2&gt;Dropping legacy support&lt;/h2&gt;
&lt;p&gt;With v1.0 at the horizon, it was also time to think about (finally) throwing out
some legacy support.&lt;/p&gt;
&lt;p&gt;I opened an issue &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/2742"&gt;to discuss&lt;/a&gt; about what'd be possible to drop, and what needs
to stay. &lt;strong&gt;If you use qutebrowser on something other than
Archlinux/Windows/macOS, this will probably affect you&lt;/strong&gt; - and I'd love your
input!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="next-few-days"&gt;
&lt;h2&gt;Next few days&lt;/h2&gt;
&lt;p&gt;As mentioned in the Kickstarter already, I'm having a planned eye surgery. I'm
leaving for the hospital tomorrow (Wednesday) and should be back home on Friday
if everything goes well.&lt;/p&gt;
&lt;p&gt;I can't say when I'll feel well enough to start coding again, but I hope that's
already early next week somewhen.&lt;/p&gt;
&lt;p&gt;Also, somewhen after next week I'll take a longer &amp;quot;break&amp;quot; because I need to
start learning for my exams coming up in August (and there's &lt;strong&gt;a lot&lt;/strong&gt; to do).&lt;/p&gt;
&lt;p&gt;This means the rest of the work (and also, taking care of the shirts) might be
postponed until September, after my exams. But it all really depends on how much
days I'll be able to do next week.&lt;/p&gt;
&lt;p&gt;Also, for the sake of transparency: I'm starting to worry whether I can really
do everything I planned during the crowdfunded time, as only 8 days are left
now. The initial refactoring took a lot more time than I thought it would. I
hope adding the Python config API will be just as easy as adding the YAML was,
but then there are still per-domain settings which probably require a bit of
work. My hope is that I'll get (a prototype of) those into the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;new-config&lt;/span&gt;&lt;/tt&gt;
branch by the end, but I'm not sure whether I'll manage to get everything merged
to &lt;tt class="docutils literal"&gt;master&lt;/tt&gt; by then.&lt;/p&gt;
&lt;p&gt;Still, of course I'm fully committed to making this happen (after my exams,
though) even in my spare time. The biggest part (hours and hours of refactoring,
essentially) is done already. It just means it might take a bit longer than
expected.&lt;/p&gt;
&lt;p&gt;Or maybe everything will work nicely and all this is unfounded.
I don't know yet.&lt;/p&gt;
&lt;/div&gt;
</content></entry><entry><title>Refactoring all the things!</title><link href="https://blog.qutebrowser.org/refactoring-all-the-things.html" rel="alternate"></link><published>2017-06-14T21:13:15+02:00</published><updated>2017-06-14T21:13:15+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2017-06-14:/refactoring-all-the-things.html</id><summary type="html">&lt;div class="section" id="new-config"&gt;
&lt;h2&gt;New config&lt;/h2&gt;
&lt;p&gt;We're on day 8 already (time flies!), and I'm almost finished refactoring the
entire qutebrowser codebase to use the new config. There are still some issues
here and there and some missing changes (for &lt;tt class="docutils literal"&gt;:set&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;qute:config&lt;/tt&gt;
mostly), but qutebrowser is now mostly usable again without needing …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="section" id="new-config"&gt;
&lt;h2&gt;New config&lt;/h2&gt;
&lt;p&gt;We're on day 8 already (time flies!), and I'm almost finished refactoring the
entire qutebrowser codebase to use the new config. There are still some issues
here and there and some missing changes (for &lt;tt class="docutils literal"&gt;:set&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;qute:config&lt;/tt&gt;
mostly), but qutebrowser is now mostly usable again without needing any of the
old config code.&lt;/p&gt;
&lt;p&gt;This took much &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/compare/new-config"&gt;more work&lt;/a&gt; than I expected, and much of it was quite tedious:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;98 files changed, 4270 insertions(+), 3865 deletions(-)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I'm glad I'm almost done with that part, the real fun (working on reading and
writing the YAML/Python files) will begin soon!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="jinja-templating"&gt;
&lt;h2&gt;Jinja templating&lt;/h2&gt;
&lt;p&gt;qutebrowser uses &lt;a class="reference external" href="http://jinja.pocoo.org/"&gt;jinja2&lt;/a&gt; as a template engine to build Qt stylesheets from
config options, and then style widgets accordingly.&lt;/p&gt;
&lt;p&gt;While refactoring the config, I noticed that it's jinja's default behavior to
not raise an exception if an attribute is invalid - instead, it just assumes an
empty default value.&lt;/p&gt;
&lt;p&gt;Because this made it very hard to find issues during the refactoring, I made my
jinja environment &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/df631c5a4a6fd5cd2f0f9d5eabdc66b56647df30"&gt;more strict&lt;/a&gt; so an &lt;tt class="docutils literal"&gt;AttributeError&lt;/tt&gt; is actually caught
when it happens.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="qtwebkit-segfaults"&gt;
&lt;h2&gt;QtWebKit segfaults&lt;/h2&gt;
&lt;p&gt;Another thing I tried to track down is why the new QtWebKit packages for
Archlinux segfault a lot - I've been getting a lot of reports about this lately,
and indeed I could reproduce a crash when writing replies on Reddit.&lt;/p&gt;
&lt;p&gt;I first thought this was some bug in the &lt;a class="reference external" href="https://lists.schokokeks.org/pipermail/qutebrowser-announce/2017-June/000017.html"&gt;updated QtWebKit-NG package&lt;/a&gt;, but
then I could reproduce it with the legacy QtWebKit package which hasn't seen any
changes in the last couple of months as well...&lt;/p&gt;
&lt;p&gt;As this segfault was affecting a lot of qutebrowser users (anyone using it on
Archlinux with QtWebKit, pretty much), I decided to dig a bit deeper into it.&lt;/p&gt;
&lt;p&gt;The segfault happens here:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;WTF::StringImpl::copyChars&amp;lt;char16_t&amp;gt;()&lt;/span&gt;
&lt;span class="err"&gt;JSC::jsSpliceSubstringsWithSeparators()&lt;/span&gt;
&lt;span class="err"&gt;JSC::replaceUsingRegExpSearch()&lt;/span&gt;
&lt;span class="err"&gt;JSC::replace()&lt;/span&gt;
&lt;span class="err"&gt;JSC::stringProtoFuncReplace()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From the stacktrace, this looked like something which would be happening when
you call &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;&amp;quot;abc&amp;quot;.replace(/a/,&lt;/span&gt; &amp;quot;b&amp;quot;)&lt;/tt&gt; in JavaScript. I tried various various
variations of that, but couldn't get it to crash.&lt;/p&gt;
&lt;p&gt;I then thought I could get JavaScript to log everything passed to &lt;tt class="docutils literal"&gt;.replace()&lt;/tt&gt;
on a string, hoping I could get the string which causes the crash.&lt;/p&gt;
&lt;p&gt;A fellow student of mine came up with this, which worked beautifully:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;})(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While I saw all those calls in the console, I didn't see the call which actually
caused the crash...&lt;/p&gt;
&lt;p&gt;So I took a closer look at the C++ stacktrace, and was able to get the string
from there. It was some 9000 chars of HTML edited via JavaScript...&lt;/p&gt;
&lt;p&gt;After some more tinkering, I was able to get it down to this example which
crashes when run in &lt;tt class="docutils literal"&gt;jsc&lt;/tt&gt;, a command-line JavaScript interpreter coming with
WebKit:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;xxxxxxxxxxxxxxAxxxxxxxxxxxxxxxxxxxxA–&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/A/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then compiled WebKitGTK (which is the upstream of QtWebKit, as strange as that
sounds) with GCC 7, and indeed it was reproducable there as well.&lt;/p&gt;
&lt;p&gt;The C++ code where it crashes turned out to be this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;copyChars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="n"&gt;numCharacters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numCharacters&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numCharacters&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;s_copyCharsInlineCutOff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;#if (CPU(X86) || CPU(X86_64))&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="n"&gt;charsPerInt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numCharacters&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;charsPerInt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="n"&gt;stopCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numCharacters&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;charsPerInt&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;srcCharacters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;destCharacters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;stopCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;charsPerInt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;destCharacters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;srcCharacters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;numCharacters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;memcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numCharacters&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is essentially an optimized version of &lt;tt class="docutils literal"&gt;memcpy&lt;/tt&gt;, which does the copying
inline when it's less than 20 (&lt;tt class="docutils literal"&gt;s_copyCharsInlineCutOff&lt;/tt&gt;) chars. Nowadays, a
simple &lt;tt class="docutils literal"&gt;memcpy&lt;/tt&gt; would probably be optimized to something equivalent, but there
we are...&lt;/p&gt;
&lt;p&gt;I first was confused about how that optimized part (in the &lt;tt class="docutils literal"&gt;#if&lt;/tt&gt;) worked
together with the &amp;quot;simple&amp;quot; part below, and how the inner loop uses &lt;tt class="docutils literal"&gt;j&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;i&lt;/tt&gt;, but eventually I got it, and was sure that part was actually fine.&lt;/p&gt;
&lt;p&gt;(The optimized part copies 4-byte blocks at once, and then the part below copies
the rest)&lt;/p&gt;
&lt;p&gt;I didn't have an idea what was wrong, but people in the &lt;tt class="docutils literal"&gt;#gcc&lt;/tt&gt; IRC channel
had: Turns out it's undefined behavior when you access an &lt;tt class="docutils literal"&gt;uint16_t*&lt;/tt&gt; via an
&lt;tt class="docutils literal"&gt;uint32_t*&lt;/tt&gt; - that was when I learned about &lt;a class="reference external" href="https://www.cocoawithlove.com/2008/04/using-pointers-to-recast-in-c-is-bad.html"&gt;type punning&lt;/a&gt; and
&lt;a class="reference external" href="http://dbp-consulting.com/tutorials/StrictAliasing.html"&gt;strict aliasing&lt;/a&gt;...&lt;/p&gt;
&lt;p&gt;And indeed, &lt;a class="reference external" href="https://github.com/annulen/webkit/issues/562#issuecomment-307911343"&gt;removing&lt;/a&gt; that optimized loop made things run fine.&lt;/p&gt;
&lt;p&gt;The &amp;quot;fun&amp;quot; thing is that WebKit is compiled using the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-fno-strict-aliasing&lt;/span&gt;&lt;/tt&gt;
flag to GCC, which should actually allow this kind of thing. Still, with GCC 6
it works fine, with GCC 7 it crashes - so this might turn out to be some kind of
GCC bug.&lt;/p&gt;
&lt;p&gt;I haven't opened an upstream WebKit bug for this yet, but I'll do so today or
tomorrow unless the QtWebKit maintainer does so.&lt;/p&gt;
&lt;p&gt;I also requested my workaround to be &lt;a class="reference external" href="https://bugs.archlinux.org/task/54428"&gt;applied&lt;/a&gt; to Archlinux' packages, but that
hasn't happened so far.&lt;/p&gt;
&lt;/div&gt;
</content></entry><entry><title>First week</title><link href="https://blog.qutebrowser.org/first-week.html" rel="alternate"></link><published>2017-06-09T22:48:36+02:00</published><updated>2017-06-12T15:35:48+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2017-06-09:/first-week.html</id><summary type="html">&lt;p&gt;Phew, days 3, 4 and 5 are over already, and it's more than time for another
update! Lots of code in this one... ;-)&lt;/p&gt;
&lt;div class="section" id="wednesday"&gt;
&lt;h2&gt;Wednesday&lt;/h2&gt;
&lt;p&gt;On Wednesday, I took a closer look at the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/pull/2295"&gt;completion refactoring&lt;/a&gt; pull request
and some sqlite performance issues it had.&lt;/p&gt;
&lt;p&gt;I was able to get the …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Phew, days 3, 4 and 5 are over already, and it's more than time for another
update! Lots of code in this one... ;-)&lt;/p&gt;
&lt;div class="section" id="wednesday"&gt;
&lt;h2&gt;Wednesday&lt;/h2&gt;
&lt;p&gt;On Wednesday, I took a closer look at the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/pull/2295"&gt;completion refactoring&lt;/a&gt; pull request
and some sqlite performance issues it had.&lt;/p&gt;
&lt;p&gt;I was able to get the performance up to an acceptable level (comparable to the
current completion, but without a web history limit, i.e. searching the full
history) by creating some &lt;a class="reference external" href="https://github.com/rcorre/qutebrowser/commit/1e016cd4404df642a87d2855621a1178a9fc1046"&gt;SQL indices&lt;/a&gt; on the table, and &lt;a class="reference external" href="https://github.com/rcorre/qutebrowser/compare/0e6b9b46b0243eaf7fee28b17d43bc5c56632993~2...rcorre:0e6b9b46b0243eaf7fee28b17d43bc5c56632993"&gt;splitting&lt;/a&gt; the
table into two so it looks more like how the data is actually displayed in the
completion. I also needed to add a &lt;a class="reference external" href="https://github.com/rcorre/qutebrowser/commit/939d2823ed3c191303d04a965cc43e3728ab819f"&gt;cache&lt;/a&gt; for QtWebKit's &lt;tt class="docutils literal"&gt;historyContains&lt;/tt&gt;
(used to color visited links) because for some reason it asked for the same
thing dozens of times in a row...&lt;/p&gt;
&lt;p&gt;After that, I did a complete &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/pull/2295#pullrequestreview-42646196"&gt;review&lt;/a&gt; of that pull request. Unfortunately it
grow quite big, so the review also took a fair amount of time...&lt;/p&gt;
&lt;p&gt;I originally planned to get it merged before starting the config work, but that
made me realize that's not feasible. However, only relatively little config code
is impacted by it, so it seems reasonable to let rcorre (the contributor doing
that PR) work in parallel on that while I'm working on the config.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="thursday"&gt;
&lt;h2&gt;Thursday&lt;/h2&gt;
&lt;p&gt;Yesterday morning I was mostly busy with finishing some work related to the
contribution above. After that, I tried updating my &lt;a class="reference external" href="https://github.com/qutebrowser/qt-debug-pkgbuild/blob/master/README.md"&gt;debug Qt packages&lt;/a&gt; for
Qt 5.9 which was &lt;a class="reference external" href="http://blog.qt.io/blog/2017/05/31/qt-5-9-released/"&gt;recently released&lt;/a&gt;, but unfortunately ran into some issues
with building them...&lt;/p&gt;
&lt;p&gt;After that, I started branching off to a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;new-config&lt;/span&gt;&lt;/tt&gt; branch - with that, the
real work (and breaking everything) could begin.&lt;/p&gt;
&lt;p&gt;I started with stubbing out all the old config code, &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/3385fe1560409a9125e5ea8713c17dac304bc0ce"&gt;replacing it&lt;/a&gt; by a simple
object which only returns the default settings.&lt;/p&gt;
&lt;p&gt;It essentially boils down to this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SectionStub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_conf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__getitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NewConfigManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QObject&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="n"&gt;changed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pyqtSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sect&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; -&amp;gt; &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_defaults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;section&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;configdata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It only provides the default config values to the rest of the code and various
stuff (like typing &lt;tt class="docutils literal"&gt;:set&lt;/tt&gt;) crashes, but it's a great foundation to build the
new config code upon, and much of the old code is deactivated with that.&lt;/p&gt;
&lt;p&gt;Next, I converted the old &lt;tt class="docutils literal"&gt;configdata.py&lt;/tt&gt; file to a YAML file, as it was very
cumbersome to edit before. The &lt;tt class="docutils literal"&gt;configdata&lt;/tt&gt; file contains the definitions of
all available qutebrowser settings, with their types, default values and
description.&lt;/p&gt;
&lt;p&gt;This is an example of how it looked:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;log-javascript-console&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;SettingValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;valid_values&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValidValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;none&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Don&amp;#39;t log messages.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;debug&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Log messages with debug level.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;info&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Log messages with info level.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;debug&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;How to log javascript console messages.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And this is how the same definition looks in the YAML file, in a more
declarative style:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;log_javascript_console&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l l-Scalar l-Scalar-Plain"&gt;type&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt;
    &lt;span class="l l-Scalar l-Scalar-Plain"&gt;name&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;String&lt;/span&gt;
    &lt;span class="l l-Scalar l-Scalar-Plain"&gt;valid_values&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt;
      &lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;none&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Don&amp;#39;t&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;log&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;messages.&amp;quot;&lt;/span&gt;
      &lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;debug&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Log&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;debug&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;level.&amp;quot;&lt;/span&gt;
      &lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;info&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Log&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;info&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;level.&amp;quot;&lt;/span&gt;
  &lt;span class="l l-Scalar l-Scalar-Plain"&gt;default&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;debug&lt;/span&gt;
  &lt;span class="l l-Scalar l-Scalar-Plain"&gt;desc&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;How&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;log&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;javascript&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;console&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;messages.&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I hope you agree that this is much more readable and maintainable!&lt;/p&gt;
&lt;p&gt;Getting it into that format involved a little bit of automation:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;yaml&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;qutebrowser.config&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;configdata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;configtypes&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;configdata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;sectname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sect&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;# {}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sectname&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;optname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;optname&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;descriptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;desc&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;descriptions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;optname&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;configtypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;valid_values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;vv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;valid_values&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
                &lt;span class="n"&gt;typ_vv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;valid_values&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;typ_vv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;typ_vv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;descriptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;vv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
                    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;vv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sectname&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;colors&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;fonts&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;new_optname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sectname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                           &lt;span class="n"&gt;optname&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;_&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;new_optname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optname&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;_&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yaml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;new_optname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="n"&gt;default_flow_style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;but still required a lot of tedious manual work. Worth it, though!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="friday"&gt;
&lt;h2&gt;Friday&lt;/h2&gt;
&lt;p&gt;Today, I continued working on the &lt;tt class="docutils literal"&gt;configdata.yml&lt;/tt&gt; file - I cleaned up various
mistakes and wrote the &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/blob/9fdc494373406732556cb2a6559c15e6dde51567/qutebrowser/config/configdata.py#L527"&gt;loading code&lt;/a&gt; to actually read that file.&lt;/p&gt;
&lt;p&gt;Then I started a &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/adba5dba301d0cba1507b92e4985b4b426f72724"&gt;first renaming&lt;/a&gt; of config options (as this will be a breaking
config change, now is the time!) to make things clearer and more consistent.&lt;/p&gt;
&lt;p&gt;I also opened &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/issues/2708"&gt;an issue&lt;/a&gt; to solicit some more feedback about what should be
renamed and how - &lt;strong&gt;please participate&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;I originally thought it wouldn't be possible to have a setting like
&lt;tt class="docutils literal"&gt;colors.statusbar.bg&lt;/tt&gt; and then another one which has the same &amp;quot;base&amp;quot;, like
&lt;tt class="docutils literal"&gt;colors.statusbar.bg.private&lt;/tt&gt; - because if you did something like
&lt;tt class="docutils literal"&gt;conf.colors.statusbar.bg = 'black'&lt;/tt&gt; in Python,
&lt;tt class="docutils literal"&gt;colors.statusbar.bg.private&lt;/tt&gt; would try to access &lt;tt class="docutils literal"&gt;.private&lt;/tt&gt; on the string
&lt;tt class="docutils literal"&gt;'black'&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;However, a small proof of concept (with lots of Python magic) shows that it's
actually possible:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConfigContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ConfigContainer(handler={!r}, prefix={!r})&amp;#39;&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_prefix&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__getattr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ConfigContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                               &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__setattr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;_&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__setattr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;{}.{}&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_prefix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;


&lt;span class="n"&gt;conf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ConfigContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;baz&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;baz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;baz&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fish&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That won't make it possible to retrieve values from the config, though - the last line will print
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;ConfigContainer(handler=&amp;lt;built-in&lt;/span&gt; function print&amp;gt;, &lt;span class="pre"&gt;prefix='foo.bar.baz.fish')&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;I'm not sure yet whether I like that. It'd be possible to get the value by calling the object
(&lt;tt class="docutils literal"&gt;conf.foo.bar.baz()&lt;/tt&gt;) but that doesn't seem very intuitive either, especially
if the same thing is going to be used in the plugin API later. I'll have to
think some more about it.&lt;/p&gt;
&lt;/div&gt;
</content></entry><entry><title>First 2 days</title><link href="https://blog.qutebrowser.org/first-2-days.html" rel="alternate"></link><published>2017-06-06T18:45:28+02:00</published><updated>2017-06-06T18:45:28+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2017-06-06:/first-2-days.html</id><summary type="html">&lt;p&gt;Today was the first day in my &amp;quot;office&amp;quot; (the local &lt;a class="reference external" href="https://www.ccczh.ch/"&gt;hackerspace&lt;/a&gt;) working on
qutebrowser, and day 2 of the crowdfunding in total!&lt;/p&gt;
&lt;p&gt;Right now I'm preparing some things for the new config to be possible, and also
finishing some work related to QtWebEngine and Qt 5.9.&lt;/p&gt;
&lt;p&gt;Here's what happened …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Today was the first day in my &amp;quot;office&amp;quot; (the local &lt;a class="reference external" href="https://www.ccczh.ch/"&gt;hackerspace&lt;/a&gt;) working on
qutebrowser, and day 2 of the crowdfunding in total!&lt;/p&gt;
&lt;p&gt;Right now I'm preparing some things for the new config to be possible, and also
finishing some work related to QtWebEngine and Qt 5.9.&lt;/p&gt;
&lt;p&gt;Here's what happened since the weekend:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Stickers for backers who don't have a t-shirt are all sent out. Let me know
when you get them!&lt;/li&gt;
&lt;li&gt;The check for the unsupported Nouveau graphic driver with QtWebEngine is now
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/a858611bb9ac392b0a08f616b4c1a4feda7c3af4"&gt;more stable&lt;/a&gt;
and also &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/4d64bcc8521e73d67c068688fd8e89b8f94433c0"&gt;can be used&lt;/a&gt;
from an already running instance with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:debug-console&lt;/span&gt;&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;Some &lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/a45de9cef2f8c292d42aa4f63bf6a1ea08557508"&gt;reply object tracking&lt;/a&gt;
which was originally introduced to help with segfaults on exit with old Qt
versions was removed as it's not needed anymore, and caused problems with the
PyQt 5.9 snapshots.&lt;/li&gt;
&lt;li&gt;Download error messages are now
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/d4f58533c0f93d423ab83d09f769a86fba88103e"&gt;displayed&lt;/a&gt;
with QtWebEngine on Qt 5.9. I've had this patch lying around for a while, but
now I could finally test it with an updated PyQt.&lt;/li&gt;
&lt;li&gt;Chromium logging messages occurring during tests are now
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/998f93dfd3458f4f9a84e6b6c3f532667ba99c23"&gt;properly parsed&lt;/a&gt;
and updated for Qt 5.9.&lt;/li&gt;
&lt;li&gt;The way defaults are handled for settings passed to the web backend was
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/1785b72393f6f4b0d4f8bd02ab8a45931efbe7ff"&gt;refactored&lt;/a&gt;
so they don't require a getter anymore (which would've gotten difficult with
the new settings, as there's no one true value anymore).&lt;/li&gt;
&lt;li&gt;While working on that, I noticed clicking an element via javascript didn't use the right setting object when using private browsing, so I
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/f9b046d766eb6ecadd3787fbdad2f04d097fd1cc"&gt;fixed&lt;/a&gt; that.&lt;/li&gt;
&lt;li&gt;Some settings which (according to past crash reports) almost nobody did modify were
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/2a32e26846b34cf668d2d21d14189934f69316a5"&gt;removed&lt;/a&gt; or
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/c69672365023d3dfb5739d104fcb98af8b44f60a"&gt;merged&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A setting got
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/0ca59f2184b1953869529be431d7985470997a49"&gt;renamed&lt;/a&gt;
to make clearer what it does. I expect to rename many more settings at a later point though.&lt;/li&gt;
&lt;li&gt;A pull request adding a &lt;tt class="docutils literal"&gt;{private}&lt;/tt&gt; field to the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;window-title&lt;/span&gt;&lt;/tt&gt; setting was
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/49b8737f7979fc878ba25aed94cc3e57f481ae3a"&gt;accepted&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tomorrow, I plan to take a closer look at a
&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/pull/2295"&gt;quite big pull request&lt;/a&gt;
(maybe even the biggest in qutebrowser's history?) refactoring most of the
completion code and fixing many issues in the process. Unfortunately it has some
performance issues, but I'd really like to get it in before starting the big
config rewriting.&lt;/p&gt;
</content></entry><entry><title>Getting started again</title><link href="https://blog.qutebrowser.org/getting-started-again.html" rel="alternate"></link><published>2017-06-03T21:32:12+02:00</published><updated>2017-06-03T21:32:12+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2017-06-03:/getting-started-again.html</id><summary type="html">&lt;p&gt;As you all probably know already, the &lt;a class="reference external" href="https://www.kickstarter.com/projects/the-compiler/qutebrowser-v10-with-per-domain-settings/description"&gt;crowdfunding&lt;/a&gt; for &lt;a class="reference external" href="https://www.qutebrowser.org/"&gt;qutebrowser&lt;/a&gt; ended
up being more than fully funded - thanks to everyone again!&lt;/p&gt;
&lt;p&gt;The funds arrived on my bank account yesterday, minus some 10% fees for
Kickstarter and payment processing. Yesterday also was the last day with
lectures before my summer holidays …&lt;/p&gt;</summary><content type="html">&lt;p&gt;As you all probably know already, the &lt;a class="reference external" href="https://www.kickstarter.com/projects/the-compiler/qutebrowser-v10-with-per-domain-settings/description"&gt;crowdfunding&lt;/a&gt; for &lt;a class="reference external" href="https://www.qutebrowser.org/"&gt;qutebrowser&lt;/a&gt; ended
up being more than fully funded - thanks to everyone again!&lt;/p&gt;
&lt;p&gt;The funds arrived on my bank account yesterday, minus some 10% fees for
Kickstarter and payment processing. Yesterday also was the last day with
lectures before my summer holidays!&lt;/p&gt;
&lt;p&gt;Since Monday is a public &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Whit_Monday"&gt;holiday&lt;/a&gt;, I decided to spend some time today on sending
out the stickers to everyone who doesn't have a t-shirt, and then continue next
Tuesday with day 2.&lt;/p&gt;
&lt;p&gt;Over the last few days, I also spent some time on getting QtWebEngine more
ready:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/086139110dc06cd3461b9b14c61a9d6f777ebe23"&gt;New private browsing which supports QtWebEngine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/blob/master/misc/qutebrowser.nsi"&gt;Windows binaries now are built with QtWebEngine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/1c6fd6f7250063c5e2d1668afb661ab26430aa57"&gt;Using legacy QtWebKit now displays a warning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/qutebrowser/qutebrowser/commit/67755e6f6caee61bd4611bb3fb9d01a4f84d9ea2"&gt;Using QtWebEngine with Nouveau shows an error instead of crashing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For people who have t-shirts in their pledges, a survey will follow soon - I
still need to sort out some things about available colors and sizes first.&lt;/p&gt;
&lt;p&gt;If you're reading this via the Python or Qt planet, note that I won't post future minor updates there - if you want updates about what I'm doing currently (a few times per week), check the &lt;a class="reference external" href="https://www.qutebrowser.org/"&gt;qutebrowser development blog&lt;/a&gt;!&lt;/p&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>Second qutebrowser crowdfunding launched!</title><link href="https://blog.qutebrowser.org/second-qutebrowser-crowdfunding-launched.html" rel="alternate"></link><published>2017-04-18T17:53:11+02:00</published><updated>2017-04-18T17:53:11+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2017-04-18:/second-qutebrowser-crowdfunding-launched.html</id><summary type="html">&lt;p&gt;Like last year, I'd love to spend my summer holidays working full-time
on qutebrowser again!&lt;/p&gt;
&lt;p&gt;This is why I started another crowdfunding - with the goal of finally
implementing the new config system. See the &lt;a class="reference external" href="https://www.kickstarter.com/projects/the-compiler/qutebrowser-v10-with-per-domain-settings?ref=1i8eaq"&gt;Kickstarter campaign&lt;/a&gt; for details.&lt;/p&gt;
&lt;p&gt;In a nutshell, that means:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;There's a separate (optional) config file, which …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;Like last year, I'd love to spend my summer holidays working full-time
on qutebrowser again!&lt;/p&gt;
&lt;p&gt;This is why I started another crowdfunding - with the goal of finally
implementing the new config system. See the &lt;a class="reference external" href="https://www.kickstarter.com/projects/the-compiler/qutebrowser-v10-with-per-domain-settings?ref=1i8eaq"&gt;Kickstarter campaign&lt;/a&gt; for details.&lt;/p&gt;
&lt;p&gt;In a nutshell, that means:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;There's a separate (optional) config file, which will never be touched
by qutebrowser, and is much better suited for people who prefer
editing their config by hand and/or managing it in a VCS like git.&lt;/li&gt;
&lt;li&gt;Many new possibilities for the config, like setting the backend
(QtWebKit/QtWebEngine), or other things which need to be available
early (like disabling canvas reading).&lt;/li&gt;
&lt;li&gt;The ability to set many settings for individual domains - such as
enabling JavaScript individually (like NoScript), or setting
user-stylesheets for some pages (like Stylish).&lt;/li&gt;
&lt;li&gt;Much more powerful configuration (in Python).&lt;/li&gt;
&lt;li&gt;Many other configuration bugs and quirks which will be fixed along the
way.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Like last year, you can get qutebrowser stickers and t-shirts by
contributing to the crowdfunding. Also, expect to see regular updates on this
blog again!&lt;/p&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>qutebrowser v0.10.0 released</title><link href="https://blog.qutebrowser.org/qutebrowser-v0100-released.html" rel="alternate"></link><published>2017-02-25T22:22:14+01:00</published><updated>2017-02-26T11:05:52+01:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2017-02-25:/qutebrowser-v0100-released.html</id><summary type="html">&lt;p&gt;I'm happy to annouce the release of qutebrowser v0.10.0!&lt;/p&gt;
&lt;p&gt;qutebrowser is a keyboard driven browser with a vim-like, minimalistic
interface. It's written using PyQt and cross-platform.&lt;/p&gt;
&lt;p&gt;I haven't announced the v0.9.0 release in this blog (or any patch releases), but
for v0.10.0 it definitely …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I'm happy to annouce the release of qutebrowser v0.10.0!&lt;/p&gt;
&lt;p&gt;qutebrowser is a keyboard driven browser with a vim-like, minimalistic
interface. It's written using PyQt and cross-platform.&lt;/p&gt;
&lt;p&gt;I haven't announced the v0.9.0 release in this blog (or any patch releases), but
for v0.10.0 it definitely makes sense to do so, as it's mostly centered on
QtWebEngine!&lt;/p&gt;
&lt;p&gt;The full changelog for this release:&lt;/p&gt;
&lt;div class="section" id="added"&gt;
&lt;h2&gt;Added&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Userscripts now have a new &lt;tt class="docutils literal"&gt;$QUTE_COMMANDLINE_TEXT&lt;/tt&gt; environment
variable, containing the current commandline contents&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;ripbang&lt;/tt&gt; userscript to create a searchengine from a duckduckgo
bang&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/annulen/webkit/wiki"&gt;QtWebKit Reloaded&lt;/a&gt; (also
called QtWebKit-NG) is now fully supported&lt;/li&gt;
&lt;li&gt;Various new functionality with the QtWebEngine backend:&lt;ul&gt;
&lt;li&gt;Printing support with Qt &amp;gt;= 5.8&lt;/li&gt;
&lt;li&gt;Proxy support with Qt &amp;gt;= 5.8&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;general &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;print-element-backgrounds&lt;/span&gt;&lt;/tt&gt; option with Qt &amp;gt;= 5.8&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;content &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;cookies-store&lt;/span&gt;&lt;/tt&gt; option&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;storage &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;cache-size&lt;/span&gt;&lt;/tt&gt; option&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;colors &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; webpage.bg&lt;/tt&gt; option&lt;/li&gt;
&lt;li&gt;The HTML5 fullscreen API (e.g. youtube videos) with QtWebEngine&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:download &lt;span class="pre"&gt;--mhtml&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;qute:history&lt;/tt&gt; URL and &lt;tt class="docutils literal"&gt;:history&lt;/tt&gt; command to show the
browsing history&lt;/li&gt;
&lt;li&gt;Open tabs are now auto-saved on each successful load and restored in
case of a crash&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:jseval&lt;/tt&gt; now has a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--file&lt;/span&gt;&lt;/tt&gt; flag so you can pass a javascript
file&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:session-save&lt;/span&gt;&lt;/tt&gt; now has a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--only-active-window&lt;/span&gt;&lt;/tt&gt; flag to only
save the active window&lt;/li&gt;
&lt;li&gt;OS X builds are back, and built with QtWebEngine&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="changed"&gt;
&lt;h2&gt;Changed&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;PyQt 5.7/Qt 5.7.1 is now required for the QtWebEngine backend&lt;/li&gt;
&lt;li&gt;Scrolling with the scrollwheel while holding shift now scrolls
sideways&lt;/li&gt;
&lt;li&gt;New way of clicking hints which solves various small issues&lt;/li&gt;
&lt;li&gt;When yanking a mailto: link via hints, the mailto: prefix is now
stripped&lt;/li&gt;
&lt;li&gt;Zoom level messages are now not stacked on top of each other anymore&lt;/li&gt;
&lt;li&gt;qutebrowser now automatically uses QtWebEngine if QtWebKit is
unavailable&lt;/li&gt;
&lt;li&gt;:history-clear now asks for a confirmation, unless it's run with
--force.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;input &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;mouse-zoom-divider&lt;/span&gt;&lt;/tt&gt; can now be 0 to disable zooming by
mouse wheel&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;network &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; proxy&lt;/tt&gt; can also be set to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pac+file://...&lt;/span&gt;&lt;/tt&gt; now to use
a local proxy autoconfig file (on QtWebKit)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="fixed"&gt;
&lt;h2&gt;Fixed&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Various bugs with Qt 5.8 and QtWebEngine:&lt;ul&gt;
&lt;li&gt;Segfault when closing a window&lt;/li&gt;
&lt;li&gt;Segfault when closing a tab with a search active&lt;/li&gt;
&lt;li&gt;Fixed various mouse actions (like automatically entering insert
mode) not working&lt;/li&gt;
&lt;li&gt;Fixed hints sometimes not working&lt;/li&gt;
&lt;li&gt;Segfault when opening a URL after a QtWebEngine renderer process
crash&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Other QtWebEngine fixes:&lt;ul&gt;
&lt;li&gt;Insert mode now gets entered correctly with a non-100% zoom&lt;/li&gt;
&lt;li&gt;Crash reports are now re-enabled when using QtWebEngine&lt;/li&gt;
&lt;li&gt;Fixed crashes when closing tabs while hinting&lt;/li&gt;
&lt;li&gt;Using :undo or :tab-clone with a &lt;a class="reference external" href="view-source://"&gt;view-source://&lt;/a&gt; or chrome:// tab
is now prevented, as it segfaults&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:enter-mode&lt;/span&gt;&lt;/tt&gt; now refuses to enter modes which can't be entered
manually (which caused crashes)&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:record-macro&lt;/span&gt;&lt;/tt&gt; (&lt;tt class="docutils literal"&gt;q&lt;/tt&gt;) now doesn't try to record macros for
special keys without a text&lt;/li&gt;
&lt;li&gt;Fixed PAC (proxy autoconfig) not working with QtWebKit&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:download &lt;span class="pre"&gt;--mhtml&lt;/span&gt;&lt;/tt&gt; now uses the new file dialog&lt;/li&gt;
&lt;li&gt;Word hints are now upper-cased correctly when hints -&amp;gt; uppercase is
true&lt;/li&gt;
&lt;li&gt;Font validation is now more permissive in the config, allowing e.g.
&amp;quot;Terminus (TTF)&amp;quot; as font name&lt;/li&gt;
&lt;li&gt;Fixed starting on newer PyQt/sip versions with LibreSSL&lt;/li&gt;
&lt;li&gt;When downloading files with QtWebKit, a User-Agent header is set when
possible&lt;/li&gt;
&lt;li&gt;Fixed showing of keybindings in the :help completion&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:navigate prev/next&lt;/tt&gt; now detects &lt;tt class="docutils literal"&gt;rel&lt;/tt&gt; attributes on &lt;tt class="docutils literal"&gt;&amp;lt;a&amp;gt;&lt;/tt&gt;
elements, and handles multiple &lt;tt class="docutils literal"&gt;rel&lt;/tt&gt; attributes correctly&lt;/li&gt;
&lt;li&gt;Fixed a crash when hinting with target &lt;tt class="docutils literal"&gt;userscript&lt;/tt&gt; and spawning a
non-existing script&lt;/li&gt;
&lt;li&gt;Lines in Jupyter notebook now trigger insert mode&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>Wrapping up and looking at the future</title><link href="https://blog.qutebrowser.org/wrapping-up-and-looking-at-the-future.html" rel="alternate"></link><published>2016-09-19T07:51:34+02:00</published><updated>2016-09-19T07:51:34+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-09-19:/wrapping-up-and-looking-at-the-future.html</id><summary type="html">&lt;div class="section" id="looking-back"&gt;
&lt;h2&gt;Looking back&lt;/h2&gt;
&lt;p&gt;As you might have noticed, it's gotten a bit more quiet here again. The reason
for that is that, unfortunately, the 40 crowd-funded days are over (plus a few
extra days), and today I'm starting to study computer science at the
&lt;a class="reference external" href="https://www.hsr.ch/Home.home.0.html?L=4"&gt;University of applied sciences in Rapperswil&lt;/a&gt; (with …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="section" id="looking-back"&gt;
&lt;h2&gt;Looking back&lt;/h2&gt;
&lt;p&gt;As you might have noticed, it's gotten a bit more quiet here again. The reason
for that is that, unfortunately, the 40 crowd-funded days are over (plus a few
extra days), and today I'm starting to study computer science at the
&lt;a class="reference external" href="https://www.hsr.ch/Home.home.0.html?L=4"&gt;University of applied sciences in Rapperswil&lt;/a&gt; (with a beautiful campus next
to the lake).&lt;/p&gt;
&lt;p&gt;As probably &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Hofstadter%27s_law"&gt;usual in software development&lt;/a&gt;, things took a bit longer than
planned - I originally thought I'd have the second month for things other than
QtWebEngine, and it didn't turn out that way. I think my guesstimates for
everything related to QtWebEngine were roughly accurate, but there was a lot of
other work (organizing crowdfunding stuff, taking care of contributions and
issues, and the occasional important bugfix/release) which took more time than
I imagined.&lt;/p&gt;
&lt;p&gt;Still I'm happy with the progress made in these two months. A few features are
still &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/666"&gt;missing&lt;/a&gt;, but I know about multiple people (myself included) using the
QtWebEngine backend as a daily driver and not really missing much.&lt;/p&gt;
&lt;p&gt;What's more important is that the big things are out of the way - the last
feature I expect to take a longer time to implement are downloads, everything
else is something I can also implement whenever I have an hour or two to spare
some evening.&lt;/p&gt;
&lt;p&gt;A lot changed in those two months! From 5th June when I wrote the
&lt;a class="reference external" href="https://blog.qutebrowser.org/about-and-timeline.html"&gt;first post here&lt;/a&gt; until now, 19538 lines were added and 9435 deleted in 375
files. Only looking at the &lt;tt class="docutils literal"&gt;qutebrowser/&lt;/tt&gt; subtree (i.e. actual source,
without tests/scripts), the numbers are a bit smaller though: 9975 added and
5701 removed lines in 124 files.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-s-next"&gt;
&lt;h2&gt;What's next&lt;/h2&gt;
&lt;p&gt;As mentioned above, today I'll start studying, so currently it's quite hard for
me to predict how much time I'll be able to spend on qutebrowser in the near
future. I expect it to roughly go back to the levels it was before the
crowdfunding started, which is still &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/graphs/contributors"&gt;a lot of activity&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As for things I plan to work on: First of all, I want to get downloads and the
other missing QtWebEngine features working. However, before that, some other
areas (namely error messages and prompts) need some bigger changes, as I don't
know which window/tab a download originated from with QtWebEngine.&lt;/p&gt;
&lt;p&gt;For messages, this was already &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/compare/5bef7dc74c26bcdc9bc2453c48e6f75daeaac5ac...e338d4b49ce8ec198ed2f000d1af4ec8cc08a42c"&gt;done&lt;/a&gt; a week ago, along with a new UI for
messages and a lot of simplified code. For prompts, there's &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/1898#issuecomment-247460199"&gt;an issue&lt;/a&gt;
collecting some ideas and information.&lt;/p&gt;
&lt;p&gt;After the remaining QtWebEngine stuff is out of the way, I plan to look at some
postponed &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pulls"&gt;pull requests&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The next big topic to tackle is the &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/499"&gt;config revolution&lt;/a&gt; which changes the way
how qutebrowser is configured (splitting the config into a &lt;a class="reference external" href="https://en.wikipedia.org/wiki/YAML"&gt;YAML&lt;/a&gt; file for the
GUI config and a simple Python config for manual configuration).&lt;/p&gt;
&lt;p&gt;After that, it's probably time for a qutebrowser v1.0 release!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="stickers-and-shirts"&gt;
&lt;h2&gt;Stickers and shirts&lt;/h2&gt;
&lt;p&gt;If your perk only contained stickers and you've not recieved them yet, please
let me know.&lt;/p&gt;
&lt;p&gt;If you didn't get anything in the crowdfunding but still would like some
stickers, please let me know as well - if there's enough interest, I'll set up
a way to get stickers with a donation.&lt;/p&gt;
&lt;p&gt;As for t-shirts: Don't panic, you didn't miss anything. This was a bigger
logistic challenge than I thought it would be, but they're ordered in the
meantime. I hope they'll arrive at a friend's place in (southern) Germany this
or next week, and then we'll need to find a weekend where we both have the time
to send them out to you. Sending them from Germany instead of Switzerland saves
me trouble with customs inside the EU and some 500€ in postage, so it's
definitely worth the hassle!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="thanks"&gt;
&lt;h2&gt;Thanks!&lt;/h2&gt;
&lt;p&gt;Finally, I'd like to thank everyone involved in the crowdfunding again. You all
made this possible, and QtWebEngine support would be nowhere where it is
without you all. It was a blast, and I hope I'll be able to do something
similar again some time in the future.&lt;/p&gt;
&lt;p&gt;Thank you!&lt;/p&gt;
&lt;/div&gt;
</content></entry><entry><title>Days 39/40/41: Lots of features!</title><link href="https://blog.qutebrowser.org/days-394041-lots-of-features.html" rel="alternate"></link><published>2016-09-07T22:44:21+02:00</published><updated>2016-09-07T22:44:21+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-09-07:/days-394041-lots-of-features.html</id><summary type="html">&lt;p&gt;A new blogpost is overdue, as I worked on qutebrowser again for the past three
days! A lot of new features arrived, and this will hopefully make QtWebEngine
usable as a daily driver for some people!&lt;/p&gt;
&lt;div class="section" id="adblocking"&gt;
&lt;h2&gt;Adblocking&lt;/h2&gt;
&lt;p&gt;Perhaps the most exciting news first: &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/02bd42cbed8a1faf606efdf107b010c2aba2d064"&gt;adblocking&lt;/a&gt; is now available with
QtWebEngine! The …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;A new blogpost is overdue, as I worked on qutebrowser again for the past three
days! A lot of new features arrived, and this will hopefully make QtWebEngine
usable as a daily driver for some people!&lt;/p&gt;
&lt;div class="section" id="adblocking"&gt;
&lt;h2&gt;Adblocking&lt;/h2&gt;
&lt;p&gt;Perhaps the most exciting news first: &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/02bd42cbed8a1faf606efdf107b010c2aba2d064"&gt;adblocking&lt;/a&gt; is now available with
QtWebEngine! The used Qt &lt;a class="reference external" href="https://doc.qt.io/qt-5/qwebengineurlrequestinfo.html"&gt;API&lt;/a&gt; is quite powerful, and hopefully will make it
possible to implement something like &lt;a class="reference external" href="https://addons.mozilla.org/en-us/firefox/addon/umatrix/"&gt;uMatrix&lt;/a&gt; for qutebrowser somewhen in the
coming months!&lt;/p&gt;
&lt;p&gt;Right now, adblocking works the same as it did with QtWebKit, using the existing
host block lists.&lt;/p&gt;
&lt;p&gt;While implementing it, I noticed an interesting issue: qutebrowser did freeze
and crash when there was an exception inside the request interceptor used to
block the request. This is probably due to it running in Chromium's IO
thread, which makes it impossible for us to display the usual crash report
window. Instead, I added the &lt;tt class="docutils literal"&gt;utils.prevent_exceptions&lt;/tt&gt; &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/blob/v0.8.2/qutebrowser/utils/utils.py#L573-L626"&gt;decorator&lt;/a&gt; in order
to simply log exceptions happening there.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="opening-windows-via-javascript"&gt;
&lt;h2&gt;Opening windows via javascript&lt;/h2&gt;
&lt;p&gt;Some people already noticed how Qt ignored javascript trying to open a new
window (via &lt;tt class="docutils literal"&gt;window.open()&lt;/tt&gt;).&lt;/p&gt;
&lt;p&gt;Support for that &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/a4cd0291a687070e05736fbb8c312e59377cc2d3"&gt;is now implemented&lt;/a&gt;, however unfortunately I did run into a
&lt;a class="reference external" href="https://bugreports.qt.io/browse/QTBUG-54419"&gt;Qt bug&lt;/a&gt; causing the qutebrowser javascript code not being loaded for windows
opened that way (or, according to that report, possibly crashing).&lt;/p&gt;
&lt;p&gt;This will be fixed in Qt 5.6.2 and 5.7.1, however neither is released yet.
Their plan is to release Qt 5.6.2 in the &lt;a class="reference external" href="http://lists.qt-project.org/pipermail/releasing/2016-August/004329.html"&gt;coming weeks&lt;/a&gt; and then release
5.7.1 after that.&lt;/p&gt;
&lt;p&gt;Those requests are currently silently &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/cf070d48f2de931bb4c00f37a1b8077ba69956a4"&gt;ignored&lt;/a&gt; with older Qt versions. I tried
adding an error message when that happens, however it was also displayed when
opening a new link using middle-/ctrl-click, and I didn't find a way to tell the
two apart.&lt;/p&gt;
&lt;p&gt;If you don't want to wait until the release and happen to be on Archlinux, you
can also use my &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/blob/master/doc/stacktrace.asciidoc#archlinux"&gt;qt-debug packages&lt;/a&gt; and set &lt;tt class="docutils literal"&gt;QUTE_QTBUG54419_PATCHED=1&lt;/tt&gt; in
your environment. Note if you do that and don't have those fixed packages
installed, stuff will break and I'll probably ignore all related crash logs ;)&lt;/p&gt;
&lt;p&gt;On other distributions, you'll need to rebuild QtWebEngine with &lt;a class="reference external" href="https://codereview.qt-project.org/gitweb?p=qt/qtwebengine.git;a=patch;h=f5ee1feeed2abbcbe6db2bf9757d692b38fcbcb1"&gt;this patch&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="session-support"&gt;
&lt;h2&gt;Session support&lt;/h2&gt;
&lt;p&gt;Another feature many people missed was support for sessions, which is now
implemented! Unfortunately (like Qt 5.6's QtWebKit), QtWebEngine has no API to
manipulate the history of a tab programmatically, so qutebrowser instead creates
a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/blob/master/qutebrowser/browser/webengine/tabhistory.py"&gt;binary stream&lt;/a&gt; in Qt's internal serialization format and then loads that.&lt;/p&gt;
&lt;p&gt;This was definitely made much easier by an existing implementation in
&lt;a class="reference external" href="https://otter-browser.org/"&gt;Otter Browser&lt;/a&gt; (thanks!) and of course by QtWebEngine/Chromium being open
source.&lt;/p&gt;
&lt;p&gt;Initially, when loading the history, qutebrowser just segfaulted. After some
debugging in Chromium's C++ code I figured out that was because I set the
current history index to 0 instead of -1 when there are no history entries.&lt;/p&gt;
&lt;p&gt;With this fixed, everything seems to work fine so far! The only thing missing
(due to missing Qt API) is storing zoom level and scroll positions for earlier
pages in the history (i.e., everything except the currently viewed one).
However, I doubt many people will notice.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="running-without-qtwebkit"&gt;
&lt;h2&gt;Running without QtWebKit&lt;/h2&gt;
&lt;p&gt;Since I wanted to get the OS X tests to run again (which lack QtWebKit due to it
being removed from the Homebrew package manager), I looked into getting
qutebrowser (and tests) to run without QtWebKit installed. After various small
changes to how things are imported, this is now the case.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="tests-and-ci"&gt;
&lt;h2&gt;Tests and CI&lt;/h2&gt;
&lt;p&gt;Until now, qutebrowser with QtWebEngine wasn't tested on CI. This now changed,
by adding a job for QtWebEngine with Archlinux.&lt;/p&gt;
&lt;p&gt;With the session support added, I was also able to activate around 150 tests
which were disabled before. This uncovered some smaller bugs like invalid URLs
&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/f2c4cedf619f89045172ce2be57ea1c8416ecead"&gt;being added&lt;/a&gt; to the history sometimes (causing a warning to be printed), or
&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/abdc604ead32b516fa69329101263bb2582ee003"&gt;cloning&lt;/a&gt; the zoom level when cloning a tab not working properly. Some tests
(mainly for scrolling) also needed some &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/85b3d08c6632462b292fea4a1ab5721550376d85"&gt;additional waiting&lt;/a&gt; since scrolling
now happens async (via javascript) with QtWebEngine.&lt;/p&gt;
&lt;p&gt;There also were various small improvements to the output when tests fail, for
cases I discovered thanks to those failing tests.&lt;/p&gt;
&lt;p&gt;Unfortunately, a handful of tests are still flaky (failing sometimes), so I
added a &lt;tt class="docutils literal"&gt;&amp;#64;qtwebengine_flaky&lt;/tt&gt; marker and &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/08302c5a5fdc63e608c628b838a926d8c66e30dc"&gt;applied&lt;/a&gt; it to all tests which fail
sometimes and I don't see an easy fix for yet.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="other-bits-and-bytes"&gt;
&lt;h2&gt;Other bits and bytes&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;qutebrowser now &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/919196714b0e4b5ac9dbb0d8d4e4f5f0a7543299"&gt;knows&lt;/a&gt; when the scroll position is at the very bottom, so
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:scroll-page&lt;/span&gt;&lt;/tt&gt; with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--bottom-navigate&lt;/span&gt;&lt;/tt&gt; works.&lt;/li&gt;
&lt;li&gt;I tried making &lt;tt class="docutils literal"&gt;colors &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; webpage.bg&lt;/tt&gt; &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/02df91e369f441160296ef9c6f38733c3d36b2d3"&gt;work&lt;/a&gt;, but without any luck.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;auto-insert-mode&lt;/span&gt;&lt;/tt&gt; setting &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/ee5a97206902cd44776966538b8296b92f38c4fe"&gt;now works&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:insert-text&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:paste-primary&lt;/span&gt;&lt;/tt&gt; commands were &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/948fa033c7339d6648af2141e88283105ffbaa31"&gt;implemented&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;webelem.classes&lt;/tt&gt; got &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/fca37abf55b1e8b1639c8a885eda99e48d48d28d"&gt;implemented for QtWebEngine&lt;/a&gt; which means the insert
mode will now work correctly with things like the ACE editor (with a
corresponding &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/522049132b24354266478b1d496950bb46233d09"&gt;test&lt;/a&gt; added).&lt;/li&gt;
&lt;li&gt;Custom HTTP headers, including the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;do-not-track&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;accept-language&lt;/span&gt;&lt;/tt&gt;
settings are now &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/44d1056e5497064b21f7c40f04fa640d8f834ad3"&gt;available&lt;/a&gt; with QtWebEngine&lt;/li&gt;
&lt;li&gt;Qt 5.6.0 or newer is now &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/4d91ccfea5c970797023ec2a496178151e90ccaa"&gt;enforced&lt;/a&gt; when using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--backend&lt;/span&gt; webengine&lt;/tt&gt;. This
will probably stay the minimum version required for QtWebEngine support, I
don't intend to add support for Qt 5.4 and 5.5.&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;Various blocks of now-unneeded or dead code got removed:&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/78d64f47916f51c51893e15e3147620424a84f62"&gt;webkitelem.focus_elem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/8f9cfcf2323c0c8dfa36fe716308a8fba0f96c48"&gt;WebKitElement.run_js_async&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/60c86a08c44efc39b4891e77c4b89cf4a3d99bad"&gt;WebKitElement.debug_text&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/3e1583bb1cf353ff8793a59ed37cdc75e6966ef5"&gt;WebKitElement.is_visible&lt;/a&gt; (made private as it's only needed with QtWebKit)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/8c3906b784df09257a0e87fa1470b9cc8e796561"&gt;BrowserPage.shouldInterruptJavaScript&lt;/a&gt; (broken due to &lt;a class="reference external" href="https://bugreports.qt.io/issues/?jql=text%20~%20%22shouldInterruptJavascript%22"&gt;an old Qt bug&lt;/a&gt; and not available with QtWebEngine)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/bac7a6eaf29418327b88b831113a75c55000c875"&gt;BrowserPage.chooseFile&lt;/a&gt; (does the same as the default implementation, and file choosing also works out-of-the box with QtWebEngine!)&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;And probably some other stuff I forgot - as you can see, a lot happened in
those three days!&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content></entry><entry><title>Days 37/38: Hints in master, tests</title><link href="https://blog.qutebrowser.org/days-3738-hints-in-master-tests.html" rel="alternate"></link><published>2016-08-19T20:23:01+02:00</published><updated>2016-08-19T20:23:01+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-08-19:/days-3738-hints-in-master-tests.html</id><summary type="html">&lt;div class="section" id="hints"&gt;
&lt;h2&gt;Hints&lt;/h2&gt;
&lt;p&gt;Yesterday I merged the &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1868"&gt;pull request&lt;/a&gt; I opened for the rewritten hint drawing
and &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/9226e3eece7be77ff9d27fae5e97ba11994c59ac"&gt;implemented&lt;/a&gt; the missing bits so only visible hints are considered.&lt;/p&gt;
&lt;p&gt;Together with some other small fixes and cleanups, I then merged the
&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/2b6f4f06986b95b2f520d7ddd484925837d5b890"&gt;qtwebengine-hints&lt;/a&gt; branch, which means hints are now working fine apart from
some corner …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="section" id="hints"&gt;
&lt;h2&gt;Hints&lt;/h2&gt;
&lt;p&gt;Yesterday I merged the &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1868"&gt;pull request&lt;/a&gt; I opened for the rewritten hint drawing
and &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/9226e3eece7be77ff9d27fae5e97ba11994c59ac"&gt;implemented&lt;/a&gt; the missing bits so only visible hints are considered.&lt;/p&gt;
&lt;p&gt;Together with some other small fixes and cleanups, I then merged the
&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/2b6f4f06986b95b2f520d7ddd484925837d5b890"&gt;qtwebengine-hints&lt;/a&gt; branch, which means hints are now working fine apart from
some corner cases with frames and iframes!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="tests"&gt;
&lt;h2&gt;Tests&lt;/h2&gt;
&lt;p&gt;I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/63c66945a439cc71db3b2166fd1174978f34dc79"&gt;added&lt;/a&gt; &lt;tt class="docutils literal"&gt;webelem.click()&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;webelem.hover()&lt;/tt&gt; methods (to get some
more code out of &lt;tt class="docutils literal"&gt;hints.py&lt;/tt&gt; and provide something useful for a future plugin
API) and added a new &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/0cef4ac2db5e572fd6a3b8654c5a2a2bfe4933f3"&gt;click-element&lt;/a&gt; command.&lt;/p&gt;
&lt;p&gt;With that command, I was able to simplify a lot of tests (which used hinting to
click elements before), and then work on getting the end-to-end tests to run
with QtWebEngine.&lt;/p&gt;
&lt;p&gt;This mostly meant implementing &lt;tt class="docutils literal"&gt;&amp;#64;qtwebengine_todo&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&amp;#64;qtwebengine_skip&lt;/tt&gt;
tags and applying them all over the testsuite where things aren't ready yet.
However, there also were some other fixes:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;yankpaste.feature&lt;/tt&gt; &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/a88adcca17615b3b043b238caeef42feb14f87be"&gt;checked&lt;/a&gt; requests despite that not being necessary,
which was flaky on QtWebEngine due to caching.&lt;/li&gt;
&lt;li&gt;Due to caching, the HTTP server used for tests would send a HTTP
&amp;quot;not modified&amp;quot; answer which needed to be &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/0b9aec873f1c1196ea87723a0c0511fac7bef74c"&gt;whitelisted&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Since hints are now async, the tests sometimes were faster than qutebrowser,
so they needed some &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/745614e45d1cbb1754af9a8fc37c2d37aeca9d3d"&gt;changes&lt;/a&gt; to wait until qutebrowser actually started
hinting.&lt;/li&gt;
&lt;li&gt;Some tests waited for a specific tab to be &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/63628d2f97150219df9b6121dcdd30801a4b6ad1"&gt;focused&lt;/a&gt; which failed because
with QtWebEngine, an internal &lt;tt class="docutils literal"&gt;QOpenGLWidget&lt;/tt&gt; actually got the focus.&lt;/li&gt;
&lt;li&gt;&amp;quot;Running without the SUID sandbox&amp;quot; was &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/788eebc1ad1d67c2e62ac32bb5bc733d1d5b4563"&gt;logged&lt;/a&gt; by QtWebEngine (fixed in
Qt 5.8) and failed the tests because it was an unknown message.&lt;/li&gt;
&lt;li&gt;Hint tests &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/63cc73d56dd7a3ad6d83866ba47f6f1e8bdeebd0"&gt;did set&lt;/a&gt; some options unavailable with QtWebEngine.&lt;/li&gt;
&lt;li&gt;Another test for &lt;tt class="docutils literal"&gt;:set&lt;/tt&gt; &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/c0c327942472a2b6f54fbd3d2e3c884f0b682960"&gt;used&lt;/a&gt; an option unavailable there.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The tests already found a handful of issues:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:fake-key&lt;/span&gt;&lt;/tt&gt; was not implemented yet, &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/c0ffcfc585f764904929e8518860bbcc336e8751"&gt;now it is&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;QtWebEngine saved titles which were autogenerated from the URL, which are
&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/dfed2f9c9c90c28ea768e72194b4d91b0fe0a771"&gt;suppressed&lt;/a&gt; now.&lt;/li&gt;
&lt;li&gt;Hinting raised a &lt;tt class="docutils literal"&gt;CommandError&lt;/tt&gt; when no hints were found outside the
command handler (since hinting is now async) and &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/2a0e503644e73336f9e3f37ee4c9d462b150fbb0"&gt;crashed&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Similarly, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:view-source&lt;/span&gt;&lt;/tt&gt; &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/ccc676c04fbbf78c0911fa6fd4ed4313b0d3c835"&gt;raised&lt;/a&gt; &lt;tt class="docutils literal"&gt;CommandError&lt;/tt&gt; when used with an
invalid URL.&lt;/li&gt;
&lt;li&gt;Some code sending custom key/mouse events &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/0557fea79e50086fdcef6b51fa1da4eeda28000b"&gt;segfaulted&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Some tests which scroll with a very big value caused a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/8da942ddc759d9dcacd4a3a5f03492d72103e0cb"&gt;memory leak&lt;/a&gt; and
thus were skipped for now until I know about a good workaround.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/2eae6a06030f72a224bad1fe258f9f0f28edae3e"&gt;decreased&lt;/a&gt; the time the testsuite waits for a log line to appear until
it timeouts when a test is marked as TODO, which made the testsuite almost 5
minutes faster!&lt;/p&gt;
&lt;p&gt;Some users also found another interesting bug: Mouse clicks are handled by an
&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/blob/master/qutebrowser/browser/mouse.py"&gt;event filter&lt;/a&gt; which then (among other things) checks if the clicked element
is editable. When closing a context menu, that event was however sent to the
&lt;tt class="docutils literal"&gt;QMenu&lt;/tt&gt;, and the filter got coordinates relative to the menu.&lt;/p&gt;
&lt;p&gt;Now when the user clicked in the area to the left or top to the panel, the
event filter got negative coordinates, which triggered an &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/blob/5ac9fe9c322868bf8a95400008dbb5f000cbbc22/qutebrowser/browser/webengine/webenginetab.py#L364-L366"&gt;assertion&lt;/a&gt; when
trying to get the element at a negative position. The solution for that was to
&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/fe11e25430f4def91fd702e478ff73cebe60dc7a"&gt;ignore&lt;/a&gt; all events not going to the main widget.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-future"&gt;
&lt;h2&gt;The future&lt;/h2&gt;
&lt;p&gt;The next two weeks, I'll attend a preparation course for university. during
which I won't have much time available for qutebrowser, so I expect it to get a
bit more quiet again.&lt;/p&gt;
&lt;p&gt;After that, I'll have another week or so until my study starts, during which I
hope to work on adblocking and some other essential smaller features.&lt;/p&gt;
&lt;p&gt;Of course, during the study I'll continue working on QtWebEngine as my time
permits, but - unfortunately - not full-time anymore.&lt;/p&gt;
&lt;/div&gt;
</content></entry><entry><title>Day 36: Hints!</title><link href="https://blog.qutebrowser.org/day-36-hints.html" rel="alternate"></link><published>2016-08-18T00:23:23+02:00</published><updated>2016-08-18T00:23:23+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-08-18:/day-36-hints.html</id><summary type="html">&lt;p&gt;Today I did a lot more work on hints! After some &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/compare/7c17af3889b15845fbccf9af07c224ca4c4dbe29...new-hints"&gt;refinements&lt;/a&gt; on my hint
drawing branch, I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1868"&gt;opened&lt;/a&gt; a pull request to get some feedback from other
developers.&lt;/p&gt;
&lt;p&gt;After that, I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/compare/new-hints...webengine-hints"&gt;continued&lt;/a&gt; working on hints for QtWebEngine, and got the basics
to work:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/hints_webengine.png"&gt;&lt;img alt="basic hints with QtWebEngine!" src="/images/hints_webengine_small.png" /&gt;&lt;/a&gt;
&lt;p&gt;However, it doesn't filter hints which …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Today I did a lot more work on hints! After some &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/compare/7c17af3889b15845fbccf9af07c224ca4c4dbe29...new-hints"&gt;refinements&lt;/a&gt; on my hint
drawing branch, I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1868"&gt;opened&lt;/a&gt; a pull request to get some feedback from other
developers.&lt;/p&gt;
&lt;p&gt;After that, I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/compare/new-hints...webengine-hints"&gt;continued&lt;/a&gt; working on hints for QtWebEngine, and got the basics
to work:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/hints_webengine.png"&gt;&lt;img alt="basic hints with QtWebEngine!" src="/images/hints_webengine_small.png" /&gt;&lt;/a&gt;
&lt;p&gt;However, it doesn't filter hints which aren't visible yet, which means its
performance is bad and the hint strings are longer than they should be.
Hopefully this will change tomorrow!&lt;/p&gt;
</content></entry><entry><title>Days 33-35: Mouse functionality, and rewriting hints</title><link href="https://blog.qutebrowser.org/days-33-35-mouse-functionality-and-rewriting-hints.html" rel="alternate"></link><published>2016-08-16T23:35:50+02:00</published><updated>2016-08-16T23:35:50+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-08-16:/days-33-35-mouse-functionality-and-rewriting-hints.html</id><summary type="html">&lt;p&gt;Past Friday and on Monday I wasn't working on qutebrowser (apart from some
usual maintaince tasks) as I was traveling to/from &lt;a class="reference external" href="http://www.evoke.eu/"&gt;Evoke&lt;/a&gt; (which was great!).
But there's a lot to write about from Wednesday, Thursday and today!&lt;/p&gt;
&lt;div class="section" id="history"&gt;
&lt;h2&gt;History&lt;/h2&gt;
&lt;p&gt;The first thing I got to work on Wednesday was the …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Past Friday and on Monday I wasn't working on qutebrowser (apart from some
usual maintaince tasks) as I was traveling to/from &lt;a class="reference external" href="http://www.evoke.eu/"&gt;Evoke&lt;/a&gt; (which was great!).
But there's a lot to write about from Wednesday, Thursday and today!&lt;/p&gt;
&lt;div class="section" id="history"&gt;
&lt;h2&gt;History&lt;/h2&gt;
&lt;p&gt;The first thing I got to work on Wednesday was the history - after &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/77531d09df3ff891f57843a0752379017c05760c"&gt;moving&lt;/a&gt; the
history implementation out of &lt;tt class="docutils literal"&gt;WebView&lt;/tt&gt;, all it took was a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/393178262eeb69ecb6e420891e2aca4dc20f5b4d"&gt;single line&lt;/a&gt; (and
a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/cc693f17caa5cfcf0a2910d89132b5095f8677e0"&gt;bugfix&lt;/a&gt; in that single line) to implement history for QtWebEngine.&lt;/p&gt;
&lt;p&gt;After that I also &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/33193d7dd4578238b18c07526c051f326821d3f5"&gt;split&lt;/a&gt; the &lt;tt class="docutils literal"&gt;history&lt;/tt&gt; module into a QtWebKit specific and a
generic file, to avoid importing QtWebKit if it's not needed.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="mouse"&gt;
&lt;h2&gt;Mouse&lt;/h2&gt;
&lt;p&gt;I moved all mouse handling to an &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/f908d29a5ff1af283d6f66e181203bdfbb26cce2"&gt;event filter&lt;/a&gt; so it was decoupled from any
QtWebKit code and - in theory - would just work with QtWebEngine.&lt;/p&gt;
&lt;p&gt;However, that &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/64afc562b60d62446c67814b77b3ff5240ad1287"&gt;took&lt;/a&gt; some more effort as QtWebEngine actually forwards all
mouse events to a &lt;tt class="docutils literal"&gt;QOpenGLWidget&lt;/tt&gt; (on which Chromium draws), and that also
seems to be swapped out sometimes...&lt;/p&gt;
&lt;p&gt;This initially just handled back/forward keys on mice which have them, but I
then gradually moved over more mouse functionality:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/1a94cb551c829f9d8db37a07d9ea476e715aa94c"&gt;Mouse wheel zooming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/3bffb71b551edcd4c39e9226e9a3691b3f2dba75"&gt;Open-target handling&lt;/a&gt; (ctrl-click / middle-click / also affects hints)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/fb07655e5614cca1eedff7a53b46d310bee96e33"&gt;Rocker gestures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/1138d068e6dbd5a15a6e74a7323c53b451ba3e40"&gt;Insert mode on click&lt;/a&gt; (also affects hints)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="hints"&gt;
&lt;h2&gt;Hints&lt;/h2&gt;
&lt;p&gt;Probably the most missed feature, and I made some important progress, though it's not quite there yet ;)&lt;/p&gt;
&lt;p&gt;Last week, I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/421b14681f21aa85b2b70b6ba1d7176e0f0404dd"&gt;moved&lt;/a&gt; some hinting code out of &lt;tt class="docutils literal"&gt;WebView&lt;/tt&gt;, and today I did a
complete &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/compare/master...new-hints"&gt;rewrite&lt;/a&gt; of how hints are drawn.&lt;/p&gt;
&lt;p&gt;In the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;new-hints&lt;/span&gt;&lt;/tt&gt; branch, hints are now simply a &lt;a class="reference external" href="http://doc.qt.io/qt-5/qlabel.html"&gt;QLabel&lt;/a&gt; shown on an
overlay over the web contents instead of being a HTML element inserted into the
page.&lt;/p&gt;
&lt;p&gt;Apart from solving some issues like &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/925"&gt;#925&lt;/a&gt; where the hints are influenced by
the page stylesheet, this makes the implementation much more straightforward and
makes it work with the same code on both backends.&lt;/p&gt;
&lt;p&gt;Initially, this looked quite wrong:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/hints_ugly.png"&gt;&lt;img alt="wrongly drawn hints" src="/images/hints_ugly_small.png" /&gt;&lt;/a&gt;
&lt;p&gt;But after getting the sizing and more styling correct, they look better:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/hints_fixed.png"&gt;&lt;img alt="correctly drawn hints" src="/images/hints_fixed_small.png" /&gt;&lt;/a&gt;
&lt;p&gt;What's quite a challenge is that the old config used WebKit gradients (as the
hint labels were actual page elements), so with the native drawing, the
configuration is quite a bit different. The opacity is also part of the color,
so I removed the &lt;tt class="docutils literal"&gt;hints &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; opacity&lt;/tt&gt; setting.&lt;/p&gt;
&lt;p&gt;I tried to auto-migrate the trivial cases (like the default setting, or similar
gradients), but for more complex existing settings qutebrowser will simply
display an error and let the user fix it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="contributions-and-maintainance"&gt;
&lt;h2&gt;Contributions and maintainance&lt;/h2&gt;
&lt;p&gt;Contributions to qutebrowser are still on their all-time high!&lt;/p&gt;
&lt;p&gt;In the past seven days, 20 pull requests got merged (and 6 new ones are still
open), and there have been dozens - if not hundreds - of comments for issues and
PRs. This is awesome, but of course also takes a bit of time ;)&lt;/p&gt;
&lt;p&gt;I also helped &lt;a class="reference external" href="https://github.com/pytest-dev/pytest/issues/1794#issuecomment-239084479"&gt;tracking down&lt;/a&gt; a bug in pytest 3.0 (not released yet) affecting
the qutebrowser testsuite. So far, nobody &lt;a class="reference external" href="https://mail.python.org/pipermail/pytest-dev/2016-August/003775.html"&gt;seems to know&lt;/a&gt; what's going on there
exactly...&lt;/p&gt;
&lt;p&gt;Other than that, a lot of other small things happened and a few bugs got fixed -
too many to list them all here!&lt;/p&gt;
&lt;/div&gt;
</content></entry><entry><title>Days 31/32: More web elements</title><link href="https://blog.qutebrowser.org/days-3132-more-web-elements.html" rel="alternate"></link><published>2016-08-09T19:40:22+02:00</published><updated>2016-08-09T19:40:22+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-08-09:/days-3132-more-web-elements.html</id><summary type="html">&lt;p&gt;Apart from &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/627f743c26f72792293126e12118d3e53f25d161"&gt;fixing&lt;/a&gt; some QtWebEngine &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/27330bd4d1ed67447ce610a0b03784e0b3baaadf"&gt;bugs&lt;/a&gt;, yesterday and today I made some
big progress with the web element code. I successfully &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/dfbadaf7c24f3245e387f33f1347c2e53d74b820"&gt;split&lt;/a&gt; the web element
code into a generic and a QtWebKit part, and then did a first &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/b8e2d5f8f6a3547fede59e1dbc8e65f5e3c7358f"&gt;implementation&lt;/a&gt;
of the web element code for QtWebEngine, which made &lt;tt class="docutils literal"&gt;:navigate prev …&lt;/tt&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Apart from &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/627f743c26f72792293126e12118d3e53f25d161"&gt;fixing&lt;/a&gt; some QtWebEngine &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/27330bd4d1ed67447ce610a0b03784e0b3baaadf"&gt;bugs&lt;/a&gt;, yesterday and today I made some
big progress with the web element code. I successfully &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/dfbadaf7c24f3245e387f33f1347c2e53d74b820"&gt;split&lt;/a&gt; the web element
code into a generic and a QtWebKit part, and then did a first &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/b8e2d5f8f6a3547fede59e1dbc8e65f5e3c7358f"&gt;implementation&lt;/a&gt;
of the web element code for QtWebEngine, which made &lt;tt class="docutils literal"&gt;:navigate prev&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;:navigate forward&lt;/tt&gt; work.&lt;/p&gt;
&lt;p&gt;After &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/9a17591fb7761bbe31c853ca01d22f1c82037944"&gt;implementing&lt;/a&gt; some more missing web element stubs (and adding a missing
&lt;tt class="docutils literal"&gt;.lower()&lt;/tt&gt; call), I got &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:open-editor&lt;/span&gt;&lt;/tt&gt; to work as well.&lt;/p&gt;
&lt;p&gt;I then noticed the javascript linter qutebrowser is using (&lt;a class="reference external" href="https://www.eslint.org/"&gt;eslint&lt;/a&gt;) didn't
actually report anything. I tracked this down to a v1.0.0 release which turns
off all rules by default, which I somehow missed. After &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/4da53480c20d2d5943be9137357ef9bdf1a34acc"&gt;reconfiguring&lt;/a&gt; it, I
had more useful output and cleaned up some style issues.&lt;/p&gt;
&lt;p&gt;Then I properly &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/6b7a39685e43a8728eaf24567b407b0f625cff7a"&gt;modularized&lt;/a&gt; the javascript code and did some other cleanups
to ensure it doesn't remain in its initial proof-of-concept state for any
longer.&lt;/p&gt;
&lt;p&gt;By chance I noticed that &lt;tt class="docutils literal"&gt;flake8&lt;/tt&gt; (one of the Python linters qutebrowser is
using) also didn't do much anymore, which was due to me not passing a file path
to it. I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/2cbb147e33bcbdf2471294c42b66da9774170fa5"&gt;fixed&lt;/a&gt; that and also &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/fb3da578c56b3b33aaee4cd8d92a5767995cfcdc"&gt;cleaned up&lt;/a&gt; some issues which went unnoticed
in the meantime.&lt;/p&gt;
&lt;p&gt;I planned to work on the hint drawing code, but since various pull requests
related to hints were opened today, I decided to postpone that to after they
are merged.&lt;/p&gt;
</content></entry><entry><title>Days 29/30: Web elements</title><link href="https://blog.qutebrowser.org/days-2930-web-elements.html" rel="alternate"></link><published>2016-08-08T09:37:17+02:00</published><updated>2016-08-08T09:37:17+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-08-08:/days-2930-web-elements.html</id><summary type="html">&lt;p&gt;A lot of code got moved around last Thursday/Friday!&lt;/p&gt;
&lt;p&gt;I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/764c23203386b10bd37271ffdd966244bf49071b"&gt;finished&lt;/a&gt; working on the web inspector, which made dealing with javascript
a lot easier! I also &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/08b70f0f4cfb102f41b1105b1b06681d30362c59"&gt;added&lt;/a&gt; a new &lt;tt class="docutils literal"&gt;utils.javascript&lt;/tt&gt; Python module for
various javascript-related utilities.&lt;/p&gt;
&lt;p&gt;While working on the Python/Javascript bridge for web elements, I noticed …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A lot of code got moved around last Thursday/Friday!&lt;/p&gt;
&lt;p&gt;I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/764c23203386b10bd37271ffdd966244bf49071b"&gt;finished&lt;/a&gt; working on the web inspector, which made dealing with javascript
a lot easier! I also &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/08b70f0f4cfb102f41b1105b1b06681d30362c59"&gt;added&lt;/a&gt; a new &lt;tt class="docutils literal"&gt;utils.javascript&lt;/tt&gt; Python module for
various javascript-related utilities.&lt;/p&gt;
&lt;p&gt;While working on the Python/Javascript bridge for web elements, I noticed the
functions I define actually &amp;quot;leak&amp;quot; to the page. For Qt 5.7 and newer, I fixed
this letting the javascript run in a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/7b211e0b65b4be30347239fb0345a5df792b7f12"&gt;different world&lt;/a&gt; which means it runs
isolated from the page's javascript, but can still access and manipulate it.
For Qt 5.6 (which I'd still like to support with QtWebEngine, due to Archlinux'
PyQt version), this change &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/94cf3fa4ff1f040329f177dbee30cd8204908fd9"&gt;broke&lt;/a&gt; compatibility, so I fixed things up and
decided to &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/0169f3a24f32e35a7701ef9f83807dc9c1946aa0"&gt;rename&lt;/a&gt; my javascript functions to make conflicts unlikely.&lt;/p&gt;
&lt;p&gt;I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/d8521f43eeb888c10de0e99df9e3b7a7c991e464"&gt;changed&lt;/a&gt; the &lt;tt class="docutils literal"&gt;tab.find_all_elements()&lt;/tt&gt; method to be async (i.e. call a
callback rather than returning the found elements), which is the groundwork to
be able to implement it for QtWebEngine. I also wrote a small first
&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/2232e7474a39353006c33b9c7b80ae638865e599"&gt;proof-of-concept&lt;/a&gt; of manipulating web elements from Python with QtWebEngine:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/jsbridge.png"&gt;&lt;img alt="Manipulating web elements" src="/images/jsbridge_small.png" /&gt;&lt;/a&gt;
&lt;p&gt;It's about as ugly as it can get, but it demonstrates that getting elements
from Python (via Javascript) and then coloring them (via Javascript) works with
QtWebEngine, which is the first step towards supporting hints, &lt;tt class="docutils literal"&gt;:navigate&lt;/tt&gt;
and editing fields with an external editor.&lt;/p&gt;
&lt;p&gt;While reading the hints code again, I realized how the &lt;tt class="docutils literal"&gt;HintManager&lt;/tt&gt; class
has grown way too big, and cleaned things up: I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/778ccad39f1962924a3755c67f82c54b9eee787b"&gt;moved&lt;/a&gt; all &lt;tt class="docutils literal"&gt;:navigate&lt;/tt&gt;
related code to its own &lt;tt class="docutils literal"&gt;qutebrowser.browser.navigate&lt;/tt&gt; module, &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/e2ae133757a6e95cbe1d5ed633289d0790ef4851"&gt;split up&lt;/a&gt;
actions (like &amp;quot;click the link&amp;quot; or &amp;quot;download the link&amp;quot;) to a separate class, and
moved the &lt;tt class="docutils literal"&gt;_resolve_url&lt;/tt&gt; function to a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/7a65559cce3e3d168be0e5d22953b930efb39fa1"&gt;webelement method&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since pytest 3.0 is going to be &lt;a class="reference external" href="https://mail.python.org/pipermail/pytest-dev/2016-August/003754.html"&gt;released&lt;/a&gt; soon, I also &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/blob/master/misc/requirements/requirements-tests-git.txt"&gt;wrote&lt;/a&gt; a
&lt;tt class="docutils literal"&gt;requirements.txt&lt;/tt&gt; file installing all test dependencies from git/hg.
Unfortunately, I &lt;a class="reference external" href="https://mail.python.org/pipermail/pytest-dev/2016-August/003756.html"&gt;found&lt;/a&gt; some issues - at least this way I could report them
before 3.0 was released!&lt;/p&gt;
&lt;p&gt;Apart from all that, there also was a big number of GitHub issues, pull
requests, and other little things - too many to mention them all here!&lt;/p&gt;
&lt;p&gt;The plan for this week is to split up &lt;tt class="docutils literal"&gt;webelem&lt;/tt&gt; into
generic/QtWebKit/QtWebEngine parts, get &lt;tt class="docutils literal"&gt;:navigate&lt;/tt&gt; to work, and then
hopefully start looking at hints.&lt;/p&gt;
</content></entry><entry><title>Days 27/28: Settings and web inspector</title><link href="https://blog.qutebrowser.org/days-2728-settings-and-web-inspector.html" rel="alternate"></link><published>2016-08-08T09:37:03+02:00</published><updated>2016-08-08T09:37:03+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-08-08:/days-2728-settings-and-web-inspector.html</id><summary type="html">&lt;p&gt;As mentioned in the last post, I wanted to look at settings and having a web
inspector before continuing to write javascript for web elements.&lt;/p&gt;
&lt;p&gt;Yesterday, just as I was getting started with splitting up settings, I noticed
a bad &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/1742"&gt;bug&lt;/a&gt; in how the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;private-browsing&lt;/span&gt;&lt;/tt&gt; setting was handled. Due to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;As mentioned in the last post, I wanted to look at settings and having a web
inspector before continuing to write javascript for web elements.&lt;/p&gt;
&lt;p&gt;Yesterday, just as I was getting started with splitting up settings, I noticed
a bad &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/1742"&gt;bug&lt;/a&gt; in how the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;private-browsing&lt;/span&gt;&lt;/tt&gt; setting was handled. Due to that,
local storage was enabled even when private browsing was turned on, until the
browser was restarted once after setting the setting.&lt;/p&gt;
&lt;p&gt;After &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/f73f3a2001c20f55640a67b1c31ed16a19d8a326"&gt;fixing&lt;/a&gt; it, I &lt;a class="reference external" href="https://lists.schokokeks.org/pipermail/qutebrowser/2016-August/000238.html"&gt;released&lt;/a&gt; v0.8.2 with that fix (and some others) on the
same day. I also &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/195b17c1ad2b25a0924d9f5e6e99e5d248695162"&gt;improved&lt;/a&gt; the release automation so the &lt;tt class="docutils literal"&gt;build_release.py&lt;/tt&gt;
script automatically uploads release artifacts to GitHub. This should
significantly cut down the time I spend on doing future releases.&lt;/p&gt;
&lt;p&gt;Today I got most settings &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/cae7eead6f305c9a91f397b8ee2b5bb0c333810d"&gt;to work&lt;/a&gt; with QtWebEngine, and marked the rest as
QtWebKit-only in the documentation.&lt;/p&gt;
&lt;p&gt;After that was done, I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/614893bdd6f338f1727b04a8f0a604d197a19046"&gt;started&lt;/a&gt; implementing support for having a web
inspector with QtWebEngine. Qt's support for that is currently quite spartanic,
so qutebrowser has to set the &lt;tt class="docutils literal"&gt;QTWEBENGINE_REMOTE_DEBUGGING&lt;/tt&gt; environment
variable early enough (which means setting &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;developer-extras&lt;/span&gt;&lt;/tt&gt; requires a
restart) and then display that port on localhost with a second
&lt;tt class="docutils literal"&gt;QWebEngineView&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;This worked just fine in a minimal example, but didn't in qutebrowser:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/inspector_broken.png"&gt;&lt;img alt="broken web inspector" src="/images/inspector_broken_small.png" /&gt;&lt;/a&gt;
&lt;p&gt;After digging into it for a while, I found out that simply accessing
&lt;tt class="docutils literal"&gt;QWebEngineSettings.globalSettings()&lt;/tt&gt; caused something in QtWebEngine which
made it read the environment variable - I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/61e0c8327a6329b3de49018679aa305442df1e82"&gt;rewrote&lt;/a&gt; the code to not
immediately call &lt;tt class="docutils literal"&gt;globalSettings&lt;/tt&gt; and the inspector started to work:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/inspector.png"&gt;&lt;img alt="web inspector" src="/images/inspector_small.png" /&gt;&lt;/a&gt;
&lt;p&gt;There are still some rough edges, but tomorrow I should be able to improve the
inspector and start working on the required javascript code.&lt;/p&gt;
</content></entry><entry><title>Day 24-26: Refactoring the WebElement API</title><link href="https://blog.qutebrowser.org/day-24-26-refactoring-the-webelement-api.html" rel="alternate"></link><published>2016-08-01T18:39:08+02:00</published><updated>2016-08-01T18:39:08+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-08-01:/day-24-26-refactoring-the-webelement-api.html</id><summary type="html">&lt;p&gt;Last Thursday I finished the WebElement API refactoring to the point where the
QtWebKit code and all related tests work normally again, and I merged the
branch.&lt;/p&gt;
&lt;p&gt;On Friday, I did some work because of a major pytest-qt release (2.0) and fixed
some other small issues. After that, I …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last Thursday I finished the WebElement API refactoring to the point where the
QtWebKit code and all related tests work normally again, and I merged the
branch.&lt;/p&gt;
&lt;p&gt;On Friday, I did some work because of a major pytest-qt release (2.0) and fixed
some other small issues. After that, I wanted to start experimenting with some
javascript to hopefully get hints working with QtWebEngine.&lt;/p&gt;
&lt;p&gt;However I noticed having a web inspector makes writing JS much easier, so I
wanted to work on that first. Then I realized there's still no setting support
for QtWebEngine yet, so that's what I decided to actually &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/066c9bf4dcf179d38a6997512386c6a0a38caef2"&gt;start working on&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Today was a &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Swiss_National_Day"&gt;public holiday&lt;/a&gt; so I took it a bit easier and mainly merged some
(7!) pull requests, and fixed some easy bugs (&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/5ec39b7540c4e9e15012c866cf4946f7a042f05c"&gt;1&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/81d0d647319bbff1ac6c079f871afacae97c6760"&gt;2&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/49699be44e9d9b88a8550dc9e914fb9ecce30c13"&gt;3&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/ef439bb916e04989cc13776a8c3b5f246cebebc1"&gt;4&lt;/a&gt;). I also
looked at some new crash reports, and &lt;a class="reference external" href="https://github.com/The-Compiler/qt-debug-pkgbuild/commit/9950622c6d0cab536f351b57e800891e8ad27e41"&gt;updated&lt;/a&gt; my patched PyQt package.&lt;/p&gt;
</content></entry><entry><title>Day 21-23: After Europython and releases</title><link href="https://blog.qutebrowser.org/day-21-23-after-europython-and-releases.html" rel="alternate"></link><published>2016-07-27T18:22:36+02:00</published><updated>2016-07-27T18:22:36+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-07-27:/day-21-23-after-europython-and-releases.html</id><summary type="html">&lt;p&gt;This week I came back from &lt;a class="reference external" href="https://ep2016.europython.eu/en/"&gt;EuroPython&lt;/a&gt; (which was awesome!), so on Monday I
was busy with responding to issues, reading crash reports and reviewing PRs
which accumulated during my &amp;quot;holiday&amp;quot;.&lt;/p&gt;
&lt;p&gt;Yesterday I &lt;a class="reference external" href="https://blog.qutebrowser.org/qutebrowser-v080-released.html"&gt;released&lt;/a&gt; qutebrowser v0.8.0, as I had to get a new release out
ASAP because of …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This week I came back from &lt;a class="reference external" href="https://ep2016.europython.eu/en/"&gt;EuroPython&lt;/a&gt; (which was awesome!), so on Monday I
was busy with responding to issues, reading crash reports and reviewing PRs
which accumulated during my &amp;quot;holiday&amp;quot;.&lt;/p&gt;
&lt;p&gt;Yesterday I &lt;a class="reference external" href="https://blog.qutebrowser.org/qutebrowser-v080-released.html"&gt;released&lt;/a&gt; qutebrowser v0.8.0, as I had to get a new release out
ASAP because of breaking changes in Qt 5.7, and enough changes for a new real
release (rather than a simple patch release) accumulated.&lt;/p&gt;
&lt;p&gt;I then noticed the OS X &lt;tt class="docutils literal"&gt;.app&lt;/tt&gt; release was broken, due to a packaging issues.
I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/2795ae947817f494c58b49959346b48779bb077c"&gt;fixed&lt;/a&gt; the build script, added a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/fb20352e3fcfb88dbea8ae3a6121497fb73758d8"&gt;smoke test&lt;/a&gt; to notice such issues in the
future, and uploaded a new package.&lt;/p&gt;
&lt;p&gt;Today, a total of four crash reports for the same &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/1690"&gt;issue&lt;/a&gt; came in (even
though nobody reported it before the release), where qutebrowser crashed when
simply doing &lt;tt class="docutils literal"&gt;:&amp;lt;enter&amp;gt;&lt;/tt&gt; due to a change how aliases are handled.&lt;/p&gt;
&lt;p&gt;So I decided to &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/9ff006746fb75de6fdff1aaa2329ccb7b29eb51c"&gt;fix&lt;/a&gt; that and do an immediate v0.8.1 &lt;a class="reference external" href="https://lists.schokokeks.org/pipermail/qutebrowser/2016-July/000235.html"&gt;release&lt;/a&gt;, since it's
likely that more people would run into this.&lt;/p&gt;
&lt;p&gt;After the release, I started &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/compare/webelem"&gt;refactoring&lt;/a&gt; the web element API which used by
hints and some other features. Now (almost) everything is behind an unified
API. This is still kind of an experiment, as I'm not 100% sure yet if I can
implement a bridge from javascript to Python for QtWebEngine (so the existing
code can continue to use the same Python API it can with QtWebKit). We'll
hopefully see later this week.&lt;/p&gt;
</content></entry><entry><title>Day 19/20: Bugs everywhere!</title><link href="https://blog.qutebrowser.org/day-1920-bugs-everywhere.html" rel="alternate"></link><published>2016-07-26T14:29:08+02:00</published><updated>2016-07-26T14:29:08+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-07-26:/day-1920-bugs-everywhere.html</id><summary type="html">&lt;p&gt;If you're a programmer, you might know these days where everything just seems
to fall apart from all the bugs you run into. Thursday and Friday were those
days for me... ;)&lt;/p&gt;
&lt;p&gt;But let's start with the things which went well first! I implemented more
scrolling functionality with QtWebEngine (&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/7adc8ab2d61c63bdcf6eba16fde90979c03725fe"&gt;7adc8ab&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/695864281bd480bbfdb9afb752a4cb47663e6f12"&gt;6958642 …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;If you're a programmer, you might know these days where everything just seems
to fall apart from all the bugs you run into. Thursday and Friday were those
days for me... ;)&lt;/p&gt;
&lt;p&gt;But let's start with the things which went well first! I implemented more
scrolling functionality with QtWebEngine (&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/7adc8ab2d61c63bdcf6eba16fde90979c03725fe"&gt;7adc8ab&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/695864281bd480bbfdb9afb752a4cb47663e6f12"&gt;6958642&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/e2c4e6301f8ffb13ad645ab93efb1b1fe436faaf"&gt;e2c4e63&lt;/a&gt;)
which means the scrolling part is now done apart from &lt;tt class="docutils literal"&gt;scroll.at_bottom()&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;I also finally was able to &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/7b9d38e438189f33551e801ac31b44cd5a082e39"&gt;track down and fix&lt;/a&gt; a bug where some config values
where set back to the default very rarely - turns out it was an accidental
&lt;tt class="docutils literal"&gt;return&lt;/tt&gt; (instead of &lt;tt class="docutils literal"&gt;continue&lt;/tt&gt;) when reading the options and there is an
option which has been removed in qutebrowser...&lt;/p&gt;
&lt;p&gt;I then wanted to investigate and fix a &lt;a class="reference external" href="https://bugreports.qt.io/browse/QTBUG-54769"&gt;crash&lt;/a&gt; I saw on exit with
QtWebEngine. I wasn't able to construct a minimal example, so I tried to gather
as much information as possible for the report. To do so, I did a special debug
build of Python so I could use &lt;a class="reference external" href="http://valgrind.org/"&gt;valgrind&lt;/a&gt; which is very useful to track down
things like this.&lt;/p&gt;
&lt;p&gt;Turns out I also needed to recompile PyQt to work with a debug build of Python.
Since I planned to do that anyways, I decided to build the newest PyQt snapshot
(which will soon be released as PyQt 5.7). qutebrowser didn't start all,
because of a &lt;a class="reference external" href="https://www.riverbankcomputing.com/pipermail/pyqt/2016-July/037749.html"&gt;off-by-one error&lt;/a&gt; in PyQt when connecting slots...&lt;/p&gt;
&lt;p&gt;After reporting both bugs, I took a look at why AppVeyor (the Windows CI
qutebrowser uses) was &lt;a class="reference external" href="https://ci.appveyor.com/project/The-Compiler/qutebrowser/build/master-3155/job/cfo40d5id37b72i1"&gt;failing&lt;/a&gt; since a few days - turns out they did some
update to their build image which now uses Python 3.5 instead of 3.4 by
default, which broke the registry hack qutebrowser was using to make sure PyQt
gets installed at the right location.&lt;/p&gt;
&lt;p&gt;After &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/701c2fe7d04a0a31ec9e70faab7bc9bf2d69d69d"&gt;fixing&lt;/a&gt; that issue, AppVeyor failed because I forgot to adjust a
Windows-only script after the recent CherryPy (webserver used for end-to-end
tests) update.&lt;/p&gt;
&lt;p&gt;That was also &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/6f65973237c327b797da8c9aad94b6cb4cbec791"&gt;fixed&lt;/a&gt;, and AppVeyor still fails for some reason I don't really
understand yet...&lt;/p&gt;
&lt;p&gt;In a new &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1637"&gt;pull request&lt;/a&gt; there were also some issues related to qutebrowser's
object registry - I think I really should get &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/640"&gt;rid of it&lt;/a&gt; rather sooner than
later, given that it also &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/1638"&gt;causes issues&lt;/a&gt; with tests added for the new tab API
on older PyQt versions. This will probably take a day or two, but it seems like
it's really needed!&lt;/p&gt;
&lt;p&gt;Right now, I'm sitting in the airplane to &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Bilbao"&gt;Bilbao&lt;/a&gt; (Spain) for the
&lt;a class="reference external" href="https://ep2016.europython.eu/en/"&gt;EuroPython&lt;/a&gt; conference, which means things will be quiet here for another
week.&lt;/p&gt;
&lt;p&gt;After that, I'll try to get everything running smooth again, get rid of the
objreg code as much as possible, and take care of the remaining missing
QtWebEngine features (like the web inspector, settings, downloads and hinting).&lt;/p&gt;
</content></entry><entry><title>qutebrowser v0.8.0 released</title><link href="https://blog.qutebrowser.org/qutebrowser-v080-released.html" rel="alternate"></link><published>2016-07-26T14:29:08+02:00</published><updated>2016-07-26T14:29:08+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-07-26:/qutebrowser-v080-released.html</id><summary type="html">&lt;p&gt;I'm happy to annouce the release of qutebrowser v0.8.0!&lt;/p&gt;
&lt;p&gt;qutebrowser is a keyboard driven browser with a vim-like, minimalistic
interface. It's written using PyQt and cross-platform.&lt;/p&gt;
&lt;p&gt;The main reason for this release is that v0.7.0 will break with
PyQt 5.7 which is soon going to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I'm happy to annouce the release of qutebrowser v0.8.0!&lt;/p&gt;
&lt;p&gt;qutebrowser is a keyboard driven browser with a vim-like, minimalistic
interface. It's written using PyQt and cross-platform.&lt;/p&gt;
&lt;p&gt;The main reason for this release is that v0.7.0 will break with
PyQt 5.7 which is soon going to be released.&lt;/p&gt;
&lt;p&gt;I decided to do a new minor release instead of a patch release as
plenty new features have accumulated already. If your distribution
can't update to v0.8.0 for some reason, backporting &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/63e466f01985abd7be275855f0af7450eb97d8e1"&gt;this patch&lt;/a&gt;
patch &lt;em&gt;should&lt;/em&gt; work, though I haven't verified this.&lt;/p&gt;
&lt;p&gt;This release also got a big refactoring to prepare for QtWebEngine
support. To my current knowledge, all issues have been smoothened out.
If not, crash reports shall now tell me. ;)&lt;/p&gt;
&lt;p&gt;You can also already start with &amp;quot;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--backend&lt;/span&gt; webengine&lt;/tt&gt;&amp;quot; with this
release to try the QtWebEngine support - however many features are
still missing.&lt;/p&gt;
&lt;p&gt;Source release and binaries for Windows/OS X are available, the Debian
packages are still work-in-progress.&lt;/p&gt;
&lt;p&gt;The full changelog for this release:&lt;/p&gt;
&lt;div class="section" id="added"&gt;
&lt;h2&gt;Added&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:repeat-command&lt;/span&gt;&lt;/tt&gt; command (mapped to &lt;tt class="docutils literal"&gt;.&lt;/tt&gt;) to repeat the last command.
Note that two former default bundings conflict with that binding, unbinding
them via &lt;tt class="docutils literal"&gt;:unbind .i&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;:unbind .o&lt;/tt&gt; is recommended.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;qute:bookmarks&lt;/tt&gt; page which displays all bookmarks and quickmarks.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:prompt-open-download&lt;/span&gt;&lt;/tt&gt; (bound to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Ctrl-X&lt;/span&gt;&lt;/tt&gt;) which can be used to open a
download directly when getting the filename prompt.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;{host}&lt;/tt&gt; replacement for tab- and window titles which evaluates
to the current host.&lt;/li&gt;
&lt;li&gt;New default binding &lt;tt class="docutils literal"&gt;;t&lt;/tt&gt; for &lt;tt class="docutils literal"&gt;:hint input&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;New variables &lt;tt class="docutils literal"&gt;$QUTE_CONFIG_DIR&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;$QUTE_DATA_DIR&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;$QUTE_DOWNLOAD_DIR&lt;/tt&gt; available for userscripts.&lt;/li&gt;
&lt;li&gt;New option &lt;tt class="docutils literal"&gt;ui&lt;/tt&gt; -&amp;gt; &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;status-position&lt;/span&gt;&lt;/tt&gt; to configure the position of the
status bar (top/bottom).&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--pdf&lt;/span&gt; &amp;lt;filename&amp;gt;&lt;/tt&gt; argument for &lt;tt class="docutils literal"&gt;:print&lt;/tt&gt; which can be used to generate a
PDF without a dialog.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="changed"&gt;
&lt;h2&gt;Changed&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:scroll-perc&lt;/span&gt;&lt;/tt&gt; now prefers a count over the argument given to it, which means
&lt;tt class="docutils literal"&gt;gg&lt;/tt&gt; can be used with a count.&lt;/li&gt;
&lt;li&gt;Aliases can now use &lt;tt class="docutils literal"&gt;;;&lt;/tt&gt; to have an alias which executed multiple commands.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:edit-url&lt;/span&gt;&lt;/tt&gt; now does nothing if the URL isn't changed in the spawned editor.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:bookmark-add&lt;/span&gt;&lt;/tt&gt; can now be passed a URL and title to add that as a bookmark
rather than the current page.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;taskadd&lt;/tt&gt; userscript to add a taskwarrior task annotated with the
current URL.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:bookmark-del&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:quickmark-del&lt;/span&gt;&lt;/tt&gt; now delete the current page's URL if none
is given.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="fixed"&gt;
&lt;h2&gt;Fixed&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Compatibility with PyQt 5.7&lt;/li&gt;
&lt;li&gt;Fixed some configuration values being lost when a config option gets removed
from qutebrowser's code.&lt;/li&gt;
&lt;li&gt;Fix crash when downloading with a full disk&lt;/li&gt;
&lt;li&gt;Using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:jump-mark&lt;/span&gt;&lt;/tt&gt; (e.g. &lt;tt class="docutils literal"&gt;''&lt;/tt&gt;) when the current URL is invalid doesn't crash
anymore.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="removed"&gt;
&lt;h2&gt;Removed&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The ability to display status messages from webpages, as well as the related
&lt;tt class="docutils literal"&gt;ui &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt;&amp;nbsp; &lt;span class="pre"&gt;display-statusbar-messages&lt;/span&gt;&lt;/tt&gt; setting.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;general &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;wrap-search&lt;/span&gt;&lt;/tt&gt; setting as searches now always wrap.
According to a quick straw poll and prior crash logs, almost nobody is using
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;wrap-search&lt;/span&gt; = false&lt;/tt&gt;, and turning off wrapping is not possible with
QtWebEngine.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:edit-url&lt;/span&gt;&lt;/tt&gt; now doesn't accept a count anymore as its behavior was confusing
and it doesn't make much sense to add a count.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since v0.7.0, the following people have contributed to qutebrowser:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Ryan Roden-Corrent&lt;/li&gt;
&lt;li&gt;Jan Verbeek&lt;/li&gt;
&lt;li&gt;Daniel Schadt&lt;/li&gt;
&lt;li&gt;Marshall Lochbaum&lt;/li&gt;
&lt;li&gt;Ismail S&lt;/li&gt;
&lt;li&gt;David Vogt&lt;/li&gt;
&lt;li&gt;Michał Góral&lt;/li&gt;
&lt;li&gt;Panashe M. Fundira&lt;/li&gt;
&lt;li&gt;Jeremy Kaplan&lt;/li&gt;
&lt;li&gt;Edgar Hipp&lt;/li&gt;
&lt;li&gt;Daryl Finlay&lt;/li&gt;
&lt;li&gt;Jean-Louis Fuchs&lt;/li&gt;
&lt;li&gt;Kevin Velghe&lt;/li&gt;
&lt;li&gt;Jakub Klinkovský&lt;/li&gt;
&lt;li&gt;Dietrich Daroch&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thank you!&lt;/p&gt;
&lt;/div&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>Day 18: Javascript</title><link href="https://blog.qutebrowser.org/day-18-javascript.html" rel="alternate"></link><published>2016-07-13T20:17:06+02:00</published><updated>2016-07-13T20:17:06+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-07-13:/day-18-javascript.html</id><summary type="html">&lt;p&gt;Today I was mostly busy with javascript related functionality and writing some
javascript:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Added &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/9c49900f9e98fc9f11115ce2bca864ece6899b59"&gt;logging&lt;/a&gt; for javascript console logging with QtWebEngine&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/e0ab70c8cff1c096d7a8d8c0ede043fe9fc57147"&gt;Don't fail&lt;/a&gt; tests with QtWebEngine &lt;tt class="docutils literal"&gt;STUB: ...&lt;/tt&gt; messages&lt;/li&gt;
&lt;li&gt;Implement :&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/b78b89f04f75c3b113e62179a863dca3395112ec"&gt;scroll-perc&lt;/a&gt; via javascript&lt;/li&gt;
&lt;li&gt;Implement :&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/602d10c495b2ba5eb3318fd346d968008625bb44"&gt;scroll-px&lt;/a&gt; and &lt;tt class="docutils literal"&gt;scroll.to_point&lt;/tt&gt; (used for e.g. marks) via javascript&lt;/li&gt;
&lt;li&gt;Implement :&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/c83a8a64dcb56e9b47aff4473a6e273b9ca7ca74"&gt;scroll-page&lt;/a&gt; via javascript&lt;/li&gt;
&lt;li&gt;Various related …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;Today I was mostly busy with javascript related functionality and writing some
javascript:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Added &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/9c49900f9e98fc9f11115ce2bca864ece6899b59"&gt;logging&lt;/a&gt; for javascript console logging with QtWebEngine&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/e0ab70c8cff1c096d7a8d8c0ede043fe9fc57147"&gt;Don't fail&lt;/a&gt; tests with QtWebEngine &lt;tt class="docutils literal"&gt;STUB: ...&lt;/tt&gt; messages&lt;/li&gt;
&lt;li&gt;Implement :&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/b78b89f04f75c3b113e62179a863dca3395112ec"&gt;scroll-perc&lt;/a&gt; via javascript&lt;/li&gt;
&lt;li&gt;Implement :&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/602d10c495b2ba5eb3318fd346d968008625bb44"&gt;scroll-px&lt;/a&gt; and &lt;tt class="docutils literal"&gt;scroll.to_point&lt;/tt&gt; (used for e.g. marks) via javascript&lt;/li&gt;
&lt;li&gt;Implement :&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/c83a8a64dcb56e9b47aff4473a6e273b9ca7ca74"&gt;scroll-page&lt;/a&gt; via javascript&lt;/li&gt;
&lt;li&gt;Various related changes to tests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also added &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/5b1cca92ab199798337d873f8a708df7acebe12a"&gt;run_js_blocking&lt;/a&gt; to the tab API which runs javascript and
returns the result. I then tried to use that API to handle getting scroll
positions, but I didn't get it to work correctly yet (loading websites now
just hangs). Things are unfortunately a bit tricky as it involves a nested
local Qt event loop and three languages (Javascript, C++, Python)... I'll
continue trying to debug it tomorrow, and I have an alternative solution not
needing a blocking JS method in mind.&lt;/p&gt;
</content></entry><entry><title>Day 17: Printing and searching</title><link href="https://blog.qutebrowser.org/day-17-printing-and-searching.html" rel="alternate"></link><published>2016-07-13T20:16:52+02:00</published><updated>2016-07-13T20:16:52+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-07-13:/day-17-printing-and-searching.html</id><summary type="html">&lt;p&gt;After looking at a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1639"&gt;pull request&lt;/a&gt; adding a &lt;tt class="docutils literal"&gt;:print &lt;span class="pre"&gt;--pdf&lt;/span&gt;&lt;/tt&gt; flag to directly
print to PDF (and an accompanying test), I noticed I totally forgot to add
printing support to the new tab API. This wasn't caught previously because
there was no test for printing (as it's hard to use …&lt;/p&gt;</summary><content type="html">&lt;p&gt;After looking at a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1639"&gt;pull request&lt;/a&gt; adding a &lt;tt class="docutils literal"&gt;:print &lt;span class="pre"&gt;--pdf&lt;/span&gt;&lt;/tt&gt; flag to directly
print to PDF (and an accompanying test), I noticed I totally forgot to add
printing support to the new tab API. This wasn't caught previously because
there was no test for printing (as it's hard to use the print dialog
programmatically).&lt;/p&gt;
&lt;p&gt;I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/cd4eff364a841b36c6fa1653ef8f0284ab1beef0"&gt;added some API&lt;/a&gt; for printing and fixed up the PR as well as the current
printing code. Unfortunately real print support is still missing upstream in
QtWebEngine, but &lt;tt class="docutils literal"&gt;:print &lt;span class="pre"&gt;--pdf&lt;/span&gt;&lt;/tt&gt; should work with QtWebEngine with a (yet to
be released) enough recent PyQt version.&lt;/p&gt;
&lt;p&gt;The PDF printing test failed on Windows - the issue wasn't entirely obvious at
first: Windows uses backslashes as path separators, but the qutebrowser
commandline (which is also used by the end-to-end tests) uses that to escape
quotes - I pushed a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/e5cab1197963cde7ff165de0273aacd35ca64fed"&gt;change&lt;/a&gt; to (almost) always escape backslashes in commands
for the tests, which fixed that and didn't break anything else.&lt;/p&gt;
&lt;p&gt;After that I took a look at the searching code, as that was probably what I
missed the most when trying to use QtWebEngine in qutebrowser to browser
documentation.&lt;/p&gt;
&lt;p&gt;I had to &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/f0da508c218ad57289bdb9268faeba7b7741a233"&gt;restructure&lt;/a&gt; things quite a bit as much was handled inside
qutebrowser's &lt;tt class="docutils literal"&gt;QWebView&lt;/tt&gt; subclass, but now searching works with QtWebEngine
as well - and it even shows the nice indicators on the scrollbar, like
Chromium:&lt;/p&gt;
&lt;img alt="scroll bar while searching" src="/images/searching.png" /&gt;
&lt;p&gt;I also ended up &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/64b32ec87d739b3df7119c7857e8dbe38429139b"&gt;removing&lt;/a&gt; support for the setting &lt;tt class="docutils literal"&gt;general &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;wrap-search&lt;/span&gt;&lt;/tt&gt;,
which now is always &lt;tt class="docutils literal"&gt;true&lt;/tt&gt;. Only very few people seemed to change that
setting, and QtWebEngine always wraps without a possibility to influence that.&lt;/p&gt;
</content></entry><entry><title>Sending out qutebrowser and pytest stickers</title><link href="https://blog.qutebrowser.org/sending-out-qutebrowser-and-pytest-stickers.html" rel="alternate"></link><published>2016-07-12T10:50:15+02:00</published><updated>2016-07-12T11:15:37+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-07-12:/sending-out-qutebrowser-and-pytest-stickers.html</id><summary type="html">&lt;p&gt;Last Thursday, I sent out 68 letters to 19 countries, containing the stickers
for the pytest and qutebrowser crowdfundings!&lt;/p&gt;
&lt;p&gt;I already had the pytest stickers for a while, and recently recieved the
qutebrowser ones as well:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/stickers/stickers_1.jpg"&gt;&lt;img alt="qutebrowser stickers" src="/images/stickers/stickers_1_small.jpg" /&gt;&lt;/a&gt;
&lt;a class="reference external image-reference" href="/images/stickers/stickers_2.jpg"&gt;&lt;img alt="qutebrowser and pytest stickers" src="/images/stickers/stickers_2_small.jpg" /&gt;&lt;/a&gt;
&lt;p&gt;As I had the data in a (somewhat messy) CSV from Indiegogo with notes …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last Thursday, I sent out 68 letters to 19 countries, containing the stickers
for the pytest and qutebrowser crowdfundings!&lt;/p&gt;
&lt;p&gt;I already had the pytest stickers for a while, and recently recieved the
qutebrowser ones as well:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/stickers/stickers_1.jpg"&gt;&lt;img alt="qutebrowser stickers" src="/images/stickers/stickers_1_small.jpg" /&gt;&lt;/a&gt;
&lt;a class="reference external image-reference" href="/images/stickers/stickers_2.jpg"&gt;&lt;img alt="qutebrowser and pytest stickers" src="/images/stickers/stickers_2_small.jpg" /&gt;&lt;/a&gt;
&lt;p&gt;As I had the data in a (somewhat messy) CSV from Indiegogo with notes added by
hand, I wrote a small &lt;a class="reference external" href="http://paste.the-compiler.org/view/7d4a13d1"&gt;script&lt;/a&gt;
to get the data from the CSV and generate &lt;a class="reference external" href="http://www.latex-project.org/"&gt;LaTeX&lt;/a&gt; via &lt;a class="reference external" href="http://jinja.pocoo.org/"&gt;jinja2&lt;/a&gt;,
which then gave me a nice PDF which I could use with window envelopes:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/stickers/mailings_1.jpg"&gt;&lt;img alt="sticker letters" src="/images/stickers/mailings_1_small.jpg" /&gt;&lt;/a&gt;
&lt;p&gt;Turns out addressing international mail correctly gets really hard when you
have the address as individual parts rather than a free text field! I
special-cased the UK and US to (hopefully) match their format, and hoped
everyone else used something like &amp;quot;1234 City&amp;quot;... See the script source for
details if you're curious.&lt;/p&gt;
&lt;p&gt;A bit later, everything was folded, and sorted by pytest/qutebrowser as well as
Switzerland/Europe/worldwide:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/stickers/mailings_2.jpg"&gt;&lt;img alt="sticker letters - folded" src="/images/stickers/mailings_2_small.jpg" /&gt;&lt;/a&gt;
&lt;p&gt;I originally was told I could get them stamped at the post office as it was
more than 50 letters - however, it turned out that's only possible if it's more
than 50 letters &lt;em&gt;per postage value&lt;/em&gt;, which wasn't the case for me... so I spent
around 120 EUR on stamps:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/stickers/stamps.jpg"&gt;&lt;img alt="A lot of Swiss stamps!" src="/images/stickers/stamps_small.jpg" /&gt;&lt;/a&gt;
&lt;p&gt;To make things worse, on most of the letters I had to stick two stamps. At
least they were self-adhesive!&lt;/p&gt;
&lt;p&gt;Some 20 minutes of sticking on stamps later, things were ready - I also sticked
another qutebrowser sticker on the envelope, as I have more than enough (and it
made it easier to see what's a pytest and what's a qutebrowser mailing):&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/stickers/mailings_3.jpg"&gt;&lt;img alt="Ready to ship!" src="/images/stickers/mailings_3_small.jpg" /&gt;&lt;/a&gt;
&lt;p&gt;And a bit later, they made their way into the post box:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/stickers/post.jpg"&gt;&lt;img alt="Post box" src="/images/stickers/post_small.jpg" /&gt;&lt;/a&gt;
&lt;p&gt;Someone from the UK already told me theirs arrived, so hopefully yours will as
well! Please let me know when it does. ;)&lt;/p&gt;
&lt;p&gt;If your pledge level also includes a t-shirt, I'll send your stickers together
with the t-shirt, which unfortunately still will take a while to arrive.
Stay tuned!&lt;/p&gt;
</content><category term="pytest"></category></entry><entry><title>Day 15/16: Merged!</title><link href="https://blog.qutebrowser.org/day-1516-merged.html" rel="alternate"></link><published>2016-07-11T19:07:23+02:00</published><updated>2016-07-12T11:15:37+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-07-11:/day-1516-merged.html</id><summary type="html">&lt;p&gt;On Friday and today (Monday) a dealt with a lot of little annoying issues, but
I finally got the &lt;tt class="docutils literal"&gt;qtwebengine&lt;/tt&gt; branch with the initial refactoring merged!&lt;/p&gt;
&lt;p&gt;After incoperating some great code review &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1629"&gt;feedback&lt;/a&gt; I got on Thursday and
doing some other cleanups, I thought I was really close to merging …&lt;/p&gt;</summary><content type="html">&lt;p&gt;On Friday and today (Monday) a dealt with a lot of little annoying issues, but
I finally got the &lt;tt class="docutils literal"&gt;qtwebengine&lt;/tt&gt; branch with the initial refactoring merged!&lt;/p&gt;
&lt;p&gt;After incoperating some great code review &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1629"&gt;feedback&lt;/a&gt; I got on Thursday and
doing some other cleanups, I thought I was really close to merging the branch.&lt;/p&gt;
&lt;p&gt;Then I noticed some places inside qutebrowser still access the QWebView via
qutebrowser's object registry, and moved things around so the tab object (i.e.
the new abstraction API) is registered instead. So far, so good.&lt;/p&gt;
&lt;p&gt;However, this suddenly made all tests using a fake &lt;tt class="docutils literal"&gt;tab&lt;/tt&gt; object segfault on
PyQt versions older than 5.6 (i.e. all test environments except Archlinux).&lt;/p&gt;
&lt;p&gt;It seems like it's somehow connected to the object registry using the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;QObject::destroyed&lt;/span&gt;&lt;/tt&gt; signal to know when to remove an object from itself, but
when trying to do so, PyQt segfaults.&lt;/p&gt;
&lt;p&gt;After trying to find out what's going on without any success, I just &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/1638"&gt;skipped&lt;/a&gt;
those tests on older PyQt versions for now so I could move on. This is clearly
not a good solution and I'll need to revisit this in the following days and
find the underlying cause...&lt;/p&gt;
&lt;p&gt;But there's better news: Today I finally could merge the branch, and with the
newest &lt;tt class="docutils literal"&gt;master&lt;/tt&gt; you can now launch qutebrowser with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--backend&lt;/span&gt; webengine&lt;/tt&gt;
to try it out!&lt;/p&gt;
&lt;p&gt;Be careful however - other than basic browsing, some scrolling and zooming not
much is working yet:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/errorpage.png"&gt;&lt;img alt="Chromium error page in qutebrowser" src="/images/errorpage_small.png" /&gt;&lt;/a&gt;
&lt;p&gt;After that worked, I mainly spent time getting QtWebKit specific code out of
qutebrowser's &lt;tt class="docutils literal"&gt;QWebView&lt;/tt&gt; subclass - either &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/e80475ed5724431188e76f1822be0bd81370b9eb"&gt;removing it entirely&lt;/a&gt; because
it's a feature nobody uses hopefully, or moving it to the new tab API so it
works with QtWebEngine as well. This made things like page load status and
progress work.&lt;/p&gt;
&lt;p&gt;I also made the end to end tests run with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--backend&lt;/span&gt; webengine&lt;/tt&gt; and only
about 300 of 500 fail ;)&lt;/p&gt;
&lt;p&gt;I used QtWebEngine with qutebrowser for a bit, and started cursing mainly
because finding text, scrolling with &lt;tt class="docutils literal"&gt;gg&lt;/tt&gt; and auto-insert-mode didn't work.
So probably those are the next things I'll get to run!&lt;/p&gt;
&lt;p&gt;Another blogpost is planned for later or tomorrow morning, showing some photos
of how I sent all stickers out - stay tuned!&lt;/p&gt;
</content></entry><entry><title>Day 13/14: Almost merged!</title><link href="https://blog.qutebrowser.org/day-1314-almost-merged.html" rel="alternate"></link><published>2016-07-07T23:41:54+02:00</published><updated>2016-07-07T23:41:54+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-07-07:/day-1314-almost-merged.html</id><summary type="html">&lt;p&gt;The past two days I was busy with getting stickers shipped out to everyone most
of the time - I'll post a dedicated blogpost about that tomorrow with some
pictures!&lt;/p&gt;
&lt;p&gt;I still got some work in the &lt;tt class="docutils literal"&gt;qtwebengine&lt;/tt&gt; branch done:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Lots and lots of cleanups and small fixes&lt;/li&gt;
&lt;li&gt;Marked failing session …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;The past two days I was busy with getting stickers shipped out to everyone most
of the time - I'll post a dedicated blogpost about that tomorrow with some
pictures!&lt;/p&gt;
&lt;p&gt;I still got some work in the &lt;tt class="docutils literal"&gt;qtwebengine&lt;/tt&gt; branch done:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Lots and lots of cleanups and small fixes&lt;/li&gt;
&lt;li&gt;Marked failing session tests as &amp;quot;expected to fail&amp;quot; for now as sessions will
get a refactoring before they're supported in QtWebEngine anyways.&lt;/li&gt;
&lt;li&gt;Got scrolling with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--backend&lt;/span&gt; webengine&lt;/tt&gt; to work&lt;/li&gt;
&lt;li&gt;Fixed mouse wheel zooming&lt;/li&gt;
&lt;li&gt;Rebased and cleaned up commits&lt;/li&gt;
&lt;li&gt;Opened a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1629"&gt;PR&lt;/a&gt; for it to solicit some feedback from other contributors. I
plan to merge it tomorrow.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And some other maintainance work:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Merged a PR exposing a &lt;tt class="docutils literal"&gt;$QUTE_CONFIG_DIR&lt;/tt&gt; (and &lt;tt class="docutils literal"&gt;DATA&lt;/tt&gt; / &lt;tt class="docutils literal"&gt;DOWNLOADS&lt;/tt&gt;) to
userscripts&lt;/li&gt;
&lt;li&gt;Merged a PR with new unit tests for completions&lt;/li&gt;
&lt;li&gt;Merged a PR making the statusbar position configurable (top/bottom)&lt;/li&gt;
&lt;li&gt;Merged a PR adding a simple issue template for GitHub&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/89cdef851d8f56b509dc04331330dd14f8ec62a1"&gt;Fixed&lt;/a&gt; an issue where eslint (javascript linting) started to fail due to a
too old node version being installed on Travis (which caused all builds to
fail)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/compare/a58c3ff0c639ae3b4d1b92713981a76586cc693c...29ee605c790a134b2aaf7bffa4bd1868b8be7213"&gt;Improved&lt;/a&gt; the version output to make it cleaner and provide some more
informations (like if QtWebEngine is installed)&lt;/li&gt;
&lt;li&gt;The usual CI version updates&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><title>Day 12: Tests running!</title><link href="https://blog.qutebrowser.org/day-12-tests-running.html" rel="alternate"></link><published>2016-07-05T23:20:41+02:00</published><updated>2016-07-05T23:20:41+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-07-05:/day-12-tests-running.html</id><summary type="html">&lt;p&gt;Today I got all end-to-end tests for the &lt;tt class="docutils literal"&gt;qtwebengine&lt;/tt&gt; branch (still with the
QtWebKit backend!) to work:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;671 passed, 9 skipped, 8 xfailed&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This means almost all qutebrowser code is now refactored to use a well-defined
API over QtWebKit!&lt;/p&gt;
&lt;p&gt;There are still some places (hints/downloads/editor) where I'm cheating …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Today I got all end-to-end tests for the &lt;tt class="docutils literal"&gt;qtwebengine&lt;/tt&gt; branch (still with the
QtWebKit backend!) to work:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;671 passed, 9 skipped, 8 xfailed&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This means almost all qutebrowser code is now refactored to use a well-defined
API over QtWebKit!&lt;/p&gt;
&lt;p&gt;There are still some places (hints/downloads/editor) where I'm cheating and
still accessing the underlying &lt;tt class="docutils literal"&gt;QWebView&lt;/tt&gt; object directly. I plan to look at
those once I have some more experience with QtWebEngine, as I currently don't
know how the API for those should look like.&lt;/p&gt;
&lt;p&gt;Probably the most difficult thing today was &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/86acf3b973c85380317c543d35fd9219d5df32ef"&gt;rewriting&lt;/a&gt; userscript code to
work with the new way how dumping a page's content will work with QtWebEngine
(async, by calling a callback when the data is ready instead of returning it).&lt;/p&gt;
&lt;p&gt;There's still some work to do, but we're getting closer to me working in the
&lt;tt class="docutils literal"&gt;master&lt;/tt&gt; branch again and having finished the first big refactoring phase.&lt;/p&gt;
&lt;p&gt;The changes in the &lt;tt class="docutils literal"&gt;qtwebengine&lt;/tt&gt; branch are quite big already:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;35 files changed, 2085 insertions(+), 867 deletions(-)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The plan for the rest of the week looks like this:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Clean up linter warnings&lt;/li&gt;
&lt;li&gt;Get the unit tests for session saving/loading to work again as they're still
broken thanks to some heavy mocking&lt;/li&gt;
&lt;li&gt;Add stub implementations for still missing QtWebEngine features so they log a
warning and do nothing instead of crash.&lt;/li&gt;
&lt;li&gt;Implement the most needed features (like scrolling)&lt;/li&gt;
&lt;li&gt;Merge &lt;tt class="docutils literal"&gt;qtwebengine&lt;/tt&gt; into &lt;tt class="docutils literal"&gt;master&lt;/tt&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At that point, people using the git version will be able to use
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--backend&lt;/span&gt; webengine&lt;/tt&gt; to play around with QtWebEngine support which will then
gradually get better and better.&lt;/p&gt;
</content></entry><entry><title>Day 10/11: Refactoring!</title><link href="https://blog.qutebrowser.org/day-1011-refactoring.html" rel="alternate"></link><published>2016-07-04T23:18:12+02:00</published><updated>2016-07-04T23:18:12+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-07-04:/day-1011-refactoring.html</id><summary type="html">&lt;p&gt;I haven't blogged on Friday, so consider this the blog post for Friday and
Monday!&lt;/p&gt;
&lt;p&gt;On Friday I had to go to the dentist again, so not as much time available as
I'd hoped. I was mainly busy with some more organizational stuff for the
crowdfunding and general maintenance. I …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I haven't blogged on Friday, so consider this the blog post for Friday and
Monday!&lt;/p&gt;
&lt;p&gt;On Friday I had to go to the dentist again, so not as much time available as
I'd hoped. I was mainly busy with some more organizational stuff for the
crowdfunding and general maintenance. I also finally added the &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/blob/master/doc/backers.asciidoc"&gt;backers&lt;/a&gt; file
to the documentation!&lt;/p&gt;
&lt;p&gt;Today I continued working on refactoring all QtWebKit-specific code so there's
a well-defined API, and most (271) end-to-end tests pass by now:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;backforward&lt;/li&gt;
&lt;li&gt;caret&lt;/li&gt;
&lt;li&gt;history&lt;/li&gt;
&lt;li&gt;javascript&lt;/li&gt;
&lt;li&gt;keyinput&lt;/li&gt;
&lt;li&gt;marks&lt;/li&gt;
&lt;li&gt;misc&lt;/li&gt;
&lt;li&gt;navigate&lt;/li&gt;
&lt;li&gt;open&lt;/li&gt;
&lt;li&gt;prompts&lt;/li&gt;
&lt;li&gt;search&lt;/li&gt;
&lt;li&gt;sessions&lt;/li&gt;
&lt;li&gt;urlmarks&lt;/li&gt;
&lt;li&gt;zoom&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following commands/features now work again with QtWebKit:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Searching&lt;/li&gt;
&lt;li&gt;Opening a new window via JS&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:undo&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:buffer&lt;/tt&gt; completion&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:follow-selected&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:debug-clear-ssl-errors&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Loading of marks&lt;/li&gt;
&lt;li&gt;Loading of sessions&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:debug-webaction&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:inspect&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:view-source&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Passing through keys to a website&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;13 tests still fail:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;downloads&lt;ul&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;test_downloading_as_mhtml_is_available&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;test_downloading_as_mhtml_with_nonascii_headers&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;test_cancelling_a_mhtml_download_issue_1535&lt;/tt&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;editor&lt;ul&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;test_spawning_an_editor_successfully&lt;/tt&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;scroll&lt;ul&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;test_scrollpage_with_a_very_big_value&lt;/tt&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;spawn&lt;ul&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;test_starting_a_userscript_which_doesnt_exist&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;test_running_spawn_with_userscript&lt;/tt&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tabs&lt;ul&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;test_buffer_with_a_matching_title&lt;/tt&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;yankpaste&lt;ul&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;test_pasting_the_primary_selection_into_an_empty_text_field&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;test_pasting_the_primary_selection_into_a_text_field_at_specific_position&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;test_pasting_the_primary_selection_into_a_text_field_with_undo&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;test_pasting_the_primary_selection_without_a_focused_field&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;test_pasting_the_primary_selection_with_a_readonly_field&lt;/tt&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;scroll&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;tabs&lt;/tt&gt; ones should be trivial fixes. For &lt;tt class="docutils literal"&gt;downloads&lt;/tt&gt;,
&lt;tt class="docutils literal"&gt;editor&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;spawn&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;yankpaste&lt;/tt&gt; some more work and extending the API
will probably be needed.&lt;/p&gt;
&lt;p&gt;I also started implementing the existing API for QtWebEngine - unfortunately
API to get the scroll position from a &lt;tt class="docutils literal"&gt;QWebEngineView&lt;/tt&gt; was only implemented
in Qt 5.7, and the current PyQt 5.6 doesn't wrap that yet.&lt;/p&gt;
&lt;p&gt;There's also no API to scroll the page - I tried emulating key presses like I
did with QtWebKit, but for some reason that did nothing at all...&lt;/p&gt;
</content></entry><entry><title>Day 9: A bit of everything</title><link href="https://blog.qutebrowser.org/day-9-a-bit-of-everything.html" rel="alternate"></link><published>2016-07-01T00:02:47+02:00</published><updated>2016-07-01T00:02:47+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-07-01:/day-9-a-bit-of-everything.html</id><summary type="html">&lt;p&gt;I'm back from the pytest sprint, which unfortunately got interrupted by me
having to get my wisdom tooth out (which started to hurt shortly before the
sprint...).&lt;/p&gt;
&lt;p&gt;I'm back on track, but yesterday and today was full with various little things
as aftermath of the sprint, and because I left …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I'm back from the pytest sprint, which unfortunately got interrupted by me
having to get my wisdom tooth out (which started to hurt shortly before the
sprint...).&lt;/p&gt;
&lt;p&gt;I'm back on track, but yesterday and today was full with various little things
as aftermath of the sprint, and because I left qutebrowser alone for almost two
weeks.&lt;/p&gt;
&lt;p&gt;Since I want to go to sleep soon, this blog post won't be as detailed as usual,
but a simple overview of work done at the sprint, yesterday, and (a lot of it!)
today.&lt;/p&gt;
&lt;p&gt;As it involves various things only tangentially related to qutebrowser, I
didn't count yesterday as a qutebrowser crowdfunding day, but I counted today.
I think that's fair.&lt;/p&gt;
&lt;p&gt;Unfortunately that means I didn't get to working on the &lt;tt class="docutils literal"&gt;qtwebengine&lt;/tt&gt; branch
at all today, but it was definitely necessary to get all those little things
done and off my mind.&lt;/p&gt;
&lt;p&gt;Stuff I worked on, roughly separated in categories:&lt;/p&gt;
&lt;div class="section" id="qutebrowser-crowdfunding"&gt;
&lt;h2&gt;qutebrowser crowdfunding&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Finalizing the sticker design (I'll follow up with a picture in a few days
when they're here!)&lt;/li&gt;
&lt;li&gt;Ordering stickers&lt;/li&gt;
&lt;li&gt;Trying to figure out what's the best way to send out dozens of letters
(parcels?) worldwide without going insane&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="qutebrowser"&gt;
&lt;h2&gt;qutebrowser&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Looking at ~20 crash reports and answering to 5 of them&lt;/li&gt;
&lt;li&gt;Reviewing/Merging a PR improving the dvorak bindings suggested in the
completion for &lt;tt class="docutils literal"&gt;hints &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; letters&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Various (more or less painless) version updates in the testing/linting
toolchain.&lt;/li&gt;
&lt;li&gt;Hiding a Qt warning appearing with Qt 5.7.0 (fixed in .1) when showing
invalid images.&lt;/li&gt;
&lt;li&gt;Reviewing/Merging a PR which prefers the given count over an argument for
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:scroll-perc&lt;/span&gt;&lt;/tt&gt;, which means &lt;tt class="docutils literal"&gt;gg&lt;/tt&gt; now can be used with a count.&lt;/li&gt;
&lt;li&gt;Trying to build Qt 5.6.1-1 for OS X (as Homebrew refuses to install binary
packages for older versions once a newer one is released, which failed the
build...), which for some reason didn't work even though it contains
QtWebKit. I ended up disabling automated tests on OS X until QtWebEngine is
ready or someone steps up to take care of it.&lt;/li&gt;
&lt;li&gt;Reviewing/Merging a PR allowing to set an alias mapped to multiple commands.&lt;/li&gt;
&lt;li&gt;Updating to the new &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pytest-bdd&lt;/span&gt;&lt;/tt&gt; release and starting to use its new tag
customization hook to make tags in qutebrowser's &lt;tt class="docutils literal"&gt;.feature&lt;/tt&gt; files simpler.
This was troublesome for frozen tests (freezing: compiling a script to an
executable) on Windows as the hook needed &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pytest-bdd&lt;/span&gt;&lt;/tt&gt; to be installed, but
as soon as that was installed the tests would fail when frozen. I ended up
only defining the hooks when not frozen.&lt;/li&gt;
&lt;li&gt;Adding documentation and a default keybinding for &lt;tt class="docutils literal"&gt;:hint inputs&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Fix for &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:jump-mark&lt;/span&gt;&lt;/tt&gt; (&lt;tt class="docutils literal"&gt;'x&lt;/tt&gt;) crashing with an invalid URL&lt;/li&gt;
&lt;li&gt;Reviewing a PR adding a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:repeat-command&lt;/span&gt;&lt;/tt&gt; command (&lt;tt class="docutils literal"&gt;.&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;Reviewing a PR adding a &lt;tt class="docutils literal"&gt;$QUTE_CONFIG&lt;/tt&gt; variable for userscripts&lt;/li&gt;
&lt;li&gt;Reviewing a PR potentially fixing an issue with configs being corrupted when
a disk runs full&lt;/li&gt;
&lt;li&gt;Reviewing a PR improving &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:edit-url&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Reviewing a PR adding tests for completion models&lt;/li&gt;
&lt;li&gt;Reviewing a PR scaling the column widths in the completion more intelligently&lt;/li&gt;
&lt;li&gt;Testing the 3.0 beta of flake8 to avoid bad surprises when it's released, and
tracking down/reporting bugs against flake8 and various plugins qutebrowser
uses.&lt;/li&gt;
&lt;li&gt;Trying to track down qutebrowser hanging for me when I open PDFs since
recently (due to an evince/GTK bug?)&lt;/li&gt;
&lt;li&gt;Triaging various issues and answering questions, as always&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="pytest"&gt;
&lt;h2&gt;pytest&lt;/h2&gt;
&lt;p&gt;I'm one of the maintainers of pytest, and since I'm taking care of
shirts/stickers for qutebrowser already, I'll also do that part for the pytest
sprint (which also had a crowdfunding).&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Getting addresses for t-shirts for people at the sprint&lt;/li&gt;
&lt;li&gt;Doing a survey for people getting t-shirts as part of the crowdfunding&lt;/li&gt;
&lt;li&gt;Designing stickers (with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;&amp;#64;kvas-it&lt;/span&gt;&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;Designing t-shirts (with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;&amp;#64;kvas-it&lt;/span&gt;&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;Ordering stickers&lt;/li&gt;
&lt;li&gt;Various long discussions about pytest 3.0&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="pytest-bdd"&gt;
&lt;h2&gt;pytest-bdd&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Adding a hook to customize how &lt;tt class="docutils literal"&gt;&amp;#64;tags&lt;/tt&gt; in &lt;tt class="docutils literal"&gt;.feature&lt;/tt&gt; files are converted
to pytest markers, which made using tags for qutebrowser much simpler (with
&lt;tt class="docutils literal"&gt;&amp;#64;olegpidsadnyi&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;Allowing spaces in tags&lt;/li&gt;
&lt;li&gt;Fixing a test with older pytest versions&lt;/li&gt;
&lt;li&gt;Releasing v2.17.0&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="pytest-qt"&gt;
&lt;h2&gt;pytest-qt&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Picking up a &lt;tt class="docutils literal"&gt;modeltest&lt;/tt&gt; branch I started almost a year ago to test Qt
models (e.g. for qutebrowser's completion models), updating it, adding tests,
and getting it merged.&lt;/li&gt;
&lt;li&gt;Changing various defaults for an upcoming major release (with &lt;tt class="docutils literal"&gt;&amp;#64;nicoddemus&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;Reviewing/Merging a PR adding a method to wait async for a predicate.&lt;/li&gt;
&lt;li&gt;Reviewing a PR making it easier to configure which Qt backend should be used.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content></entry><entry><title>Day 8: More fixing and pytest sprint/training</title><link href="https://blog.qutebrowser.org/day-8-more-fixing-and-pytest-sprinttraining.html" rel="alternate"></link><published>2016-06-16T11:05:15+02:00</published><updated>2016-07-12T11:15:37+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-06-16:/day-8-more-fixing-and-pytest-sprinttraining.html</id><summary type="html">&lt;p&gt;(This blog post is actually a day late as I was busy packing for the pytest
sprint yesterday)&lt;/p&gt;
&lt;p&gt;Not too much exciting stuff this time - I mostly continued working on getting
basic stuff like scrolling and zooming to work after the refactoring, and added
a temporary fix for &lt;tt class="docutils literal"&gt;:navigate&lt;/tt&gt; and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;(This blog post is actually a day late as I was busy packing for the pytest
sprint yesterday)&lt;/p&gt;
&lt;p&gt;Not too much exciting stuff this time - I mostly continued working on getting
basic stuff like scrolling and zooming to work after the refactoring, and added
a temporary fix for &lt;tt class="docutils literal"&gt;:navigate&lt;/tt&gt; and hinting until I get to rewriting them for
QtWebEngine.&lt;/p&gt;
&lt;div class="section" id="pytest-sprint-and-training"&gt;
&lt;h2&gt;pytest sprint and training&lt;/h2&gt;
&lt;p&gt;For the rest of this month, I won't be working on qutebrowser much, as I'll be
at the &lt;a class="reference external" href="http://pytest.org/latest/announce/sprint2016.html"&gt;pytest sprint&lt;/a&gt; in Freiburg. However, I plan to work on various things
I need in qutebrowser's testsuite too!&lt;/p&gt;
&lt;p&gt;After the sprint, 27th to 29th, I'll host a professional &lt;a class="reference external" href="http://www.python-academy.com/courses/specialtopics/python_course_testing.html"&gt;training&lt;/a&gt; for
&lt;a class="reference external" href="http://www.pytest.org/"&gt;pytest&lt;/a&gt;, &lt;a class="reference external" href="http://tox.testrun.org/"&gt;tox&lt;/a&gt; and &lt;a class="reference external" href="http://doc.devpi.net/"&gt;devpi&lt;/a&gt; in Freiburg. If you'd like to join as well,
there are still free spaces!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="my-office"&gt;
&lt;h2&gt;My &amp;quot;office&amp;quot;&lt;/h2&gt;
&lt;p&gt;Some people wondered if I'm working from home - to avoid distractions, I'm
actually using the local &lt;a class="reference external" href="https://ccczh.ch/Hackerspace/"&gt;hackerspace&lt;/a&gt; as my &amp;quot;office&amp;quot;. Here's how it looks:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/office.png"&gt;&lt;img alt="my workplace for qutebrowser" src="/images/office_small.png" /&gt;&lt;/a&gt;
&lt;/div&gt;
</content><category term="pytest"></category><category term="pyplanet"></category></entry><entry><title>Day 7: Fixing things</title><link href="https://blog.qutebrowser.org/day-7-fixing-things.html" rel="alternate"></link><published>2016-06-14T21:23:53+02:00</published><updated>2016-07-12T11:15:37+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-06-14:/day-7-fixing-things.html</id><summary type="html">&lt;div class="section" id="handling-callbacks"&gt;
&lt;h2&gt;Handling callbacks&lt;/h2&gt;
&lt;p&gt;I did a small experiment today, trying to make it easier to use QtWebEngine
functions which expect a callback, like &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;QWebEnginePage::runJavaScript&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Normally, you'd call such a function like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;data: {}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runJavaScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1 + 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What I …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="section" id="handling-callbacks"&gt;
&lt;h2&gt;Handling callbacks&lt;/h2&gt;
&lt;p&gt;I did a small experiment today, trying to make it easier to use QtWebEngine
functions which expect a callback, like &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;QWebEnginePage::runJavaScript&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Normally, you'd call such a function like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;data: {}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runJavaScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1 + 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What I wanted is to (ab)use Python's &lt;tt class="docutils literal"&gt;yield&lt;/tt&gt; statement instead (as a
&lt;a class="reference external" href="https://www.python.org/dev/peps/pep-0342/"&gt;coroutine&lt;/a&gt;), so I can yield a callback to call, and the rest of the function
would run after it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nd"&gt;@wrap_cb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runJavaScript&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;1 + 1&amp;#39;&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;data: {}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This worked fine, and the &lt;tt class="docutils literal"&gt;wrap_cb&lt;/tt&gt; decorator looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrap_cb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="nd"&gt;@functools.wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;StopIteration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;pass&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;cb_func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;cb_func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;
        &lt;span class="n"&gt;cb_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_send&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the end I ended up not using it though, because it felt like too much magic.&lt;/p&gt;
&lt;p&gt;Definitely was an interesting experiment, and I'm a step closer wrapping my head
around how coroutines work.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="qtwebengine-branch"&gt;
&lt;h2&gt;QtWebEngine branch&lt;/h2&gt;
&lt;p&gt;Yesterday, I &lt;a class="reference external" href="https://blog.qutebrowser.org/day-6-branching-off.html"&gt;branched off&lt;/a&gt; a &lt;tt class="docutils literal"&gt;qtwebengine&lt;/tt&gt; branch, and started refactoring
everything so there would be a clearly defined interface which hides the
implementation details of a single tab in qutebrowser (&lt;tt class="docutils literal"&gt;QWebView&lt;/tt&gt; or
&lt;tt class="docutils literal"&gt;QWebEngineView&lt;/tt&gt;).&lt;/p&gt;
&lt;p&gt;This means even the current QtWebKit backend broke, which is why the work is
still in a branch. I got both QtWebKit and QtWebEngine to run enough to show you
a nice &lt;a class="reference external" href="/images/day_6.png"&gt;screenshot&lt;/a&gt;, but as soon as you do anything except opening an URL (like
scrolling, or going back/forward) qutebrowser crashed.&lt;/p&gt;
&lt;p&gt;Today I worked on getting everything running with QtWebKit first again, and expanding the
&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/blob/qtwebengine/qutebrowser/browser/tab.py"&gt;API of a tab&lt;/a&gt;. Here's what's working so far:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Scrolling&lt;/li&gt;
&lt;li&gt;Going back/forward&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:debug-dump-page&lt;/span&gt;&lt;/tt&gt; (needed for tests)&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:jseval&lt;/tt&gt; (needed for tests)&lt;/li&gt;
&lt;li&gt;Caret browsing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Everything apart from that is either broken or untested - but it's a start!&lt;/p&gt;
&lt;p&gt;Seeing the first tests pass definitely was a satisfying feeling :)&lt;/p&gt;
&lt;/div&gt;
</content><category term="pyplanet"></category></entry><entry><title>Day 6: Branching off</title><link href="https://blog.qutebrowser.org/day-6-branching-off.html" rel="alternate"></link><published>2016-06-13T18:08:10+02:00</published><updated>2016-07-12T11:15:37+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-06-13:/day-6-branching-off.html</id><summary type="html">&lt;p&gt;After &lt;a class="reference external" href="https://blog.qutebrowser.org/qutebrowser-v070-released.html"&gt;releasing&lt;/a&gt; v0.7.0 last Friday, I could finally start refactoring stuff
for QtWebEngine support today.&lt;/p&gt;
&lt;p&gt;Nothing really works properly yet, but I was able to open a website:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/day_6.png"&gt;&lt;img alt="qutebrowser with QtWebEngine user agent" src="/images/day_6_small.png" /&gt;&lt;/a&gt;
&lt;p&gt;I also merged a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1570"&gt;pull request&lt;/a&gt; to master which adds a &lt;tt class="docutils literal"&gt;{host}&lt;/tt&gt; replacement
for the title/tab-title format settings, and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;After &lt;a class="reference external" href="https://blog.qutebrowser.org/qutebrowser-v070-released.html"&gt;releasing&lt;/a&gt; v0.7.0 last Friday, I could finally start refactoring stuff
for QtWebEngine support today.&lt;/p&gt;
&lt;p&gt;Nothing really works properly yet, but I was able to open a website:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/day_6.png"&gt;&lt;img alt="qutebrowser with QtWebEngine user agent" src="/images/day_6_small.png" /&gt;&lt;/a&gt;
&lt;p&gt;I also merged a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1570"&gt;pull request&lt;/a&gt; to master which adds a &lt;tt class="docutils literal"&gt;{host}&lt;/tt&gt; replacement
for the title/tab-title format settings, and reviewed two other new pull
requests:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1577"&gt;Aliases with multiple commands&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1572"&gt;Unit tests for completion models&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><title>qutebrowser v0.7.0 released</title><link href="https://blog.qutebrowser.org/qutebrowser-v070-released.html" rel="alternate"></link><published>2016-06-10T15:55:57+02:00</published><updated>2016-06-10T15:55:57+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-06-10:/qutebrowser-v070-released.html</id><summary type="html">&lt;p&gt;I'm happy to annouce the release of qutebrowser v0.7.0!&lt;/p&gt;
&lt;p&gt;qutebrowser is a keyboard driven browser with a vim-like, minimalistic
interface. It's written using PyQt and cross-platform.&lt;/p&gt;
&lt;p&gt;As usual the source release is available, binary releases
(Windows as usual, and now also a standalone OS X .app/.dmg and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I'm happy to annouce the release of qutebrowser v0.7.0!&lt;/p&gt;
&lt;p&gt;qutebrowser is a keyboard driven browser with a vim-like, minimalistic
interface. It's written using PyQt and cross-platform.&lt;/p&gt;
&lt;p&gt;As usual the source release is available, binary releases
(Windows as usual, and now also a standalone OS X .app/.dmg and a
Debian .deb) will follow ASAP (but might be Monday until everything is
taken care of).&lt;/p&gt;
&lt;p&gt;This is a really exciting release! It comes with fixes for a few
long-standing bugs (like being able to use :hint spawn with flags or
sharing of cookies between tabs with private browsing) and includes
many new features (like marks to remember the scroll position).&lt;/p&gt;
&lt;p&gt;It also comes with a greatly improved hint and history implementation:
Hints now work more reliably in some corner cases, and gained a few
new features and other bugfixes. The history completion now contains
titles and handles redirects.&lt;/p&gt;
&lt;p&gt;And there's a lot more than that - see the full changelog:&lt;/p&gt;
&lt;div class="section" id="added"&gt;
&lt;h2&gt;Added&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:edit-url&lt;/span&gt;&lt;/tt&gt; command to edit the URL in an external editor.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;network &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;custom-headers&lt;/span&gt;&lt;/tt&gt; setting to send custom headers with every request.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;{url:pretty}&lt;/tt&gt; commandline replacement which gets replaced by the decoded URL.&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;New marks to remember a scroll position:&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last"&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:jump-mark&lt;/span&gt;&lt;/tt&gt; command to jump to a mark, bound to &lt;tt class="docutils literal"&gt;'&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:set-mark&lt;/span&gt;&lt;/tt&gt; command to set a mark, bound to ` (backtick)&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;'&lt;/tt&gt; mark gets set when moving away (hinting link with anchor, searching, etc.) so you can move back with &lt;tt class="docutils literal"&gt;''&lt;/tt&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--force-color&lt;/span&gt;&lt;/tt&gt; argument to force colored logging even if stdout is not a
terminal&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;:messages&lt;/tt&gt; command to show error messages&lt;/li&gt;
&lt;li&gt;New pop-up showing possible keybinding when the first key of a keychain is
pressed. This can be turned off using &lt;tt class="docutils literal"&gt;:set ui &lt;span class="pre"&gt;keyhint-blacklist&lt;/span&gt; *&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;hints &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;auto-follow-timeout&lt;/span&gt;&lt;/tt&gt; setting to ignore keypresses after
following a hint when filtering in number mode.&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:history-clear&lt;/span&gt;&lt;/tt&gt; command to clear the entire history&lt;/li&gt;
&lt;li&gt;New &lt;tt class="docutils literal"&gt;hints &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;find-implementation&lt;/span&gt;&lt;/tt&gt; to select which implementation (JS/Python)
should be used to find hints on a page. The &lt;tt class="docutils literal"&gt;javascript&lt;/tt&gt; implementation is
better, but slower.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="changed"&gt;
&lt;h2&gt;Changed&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;qutebrowser got a new (slightly updated) logo&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:tab-focus&lt;/span&gt;&lt;/tt&gt; can now take a negative index to focus the nth tab counted from
the right.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:yank&lt;/tt&gt; can now yank the pretty/decoded URL by adding &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--pretty&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:navigate&lt;/tt&gt; now clears the URL fragment&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:completion-item-del&lt;/span&gt;&lt;/tt&gt; (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Ctrl-D&lt;/span&gt;&lt;/tt&gt;) can now be used in &lt;tt class="docutils literal"&gt;:buffer&lt;/tt&gt; completion to
close a tab&lt;/li&gt;
&lt;li&gt;Counts can now be used with special keybindings (e.g. with modifiers)&lt;/li&gt;
&lt;li&gt;Various SSL ciphers are now disabled by default. With recent Qt/OpenSSL
versions those already all are disabled, but with older versions they might
not be.&lt;/li&gt;
&lt;li&gt;Show favicons as window icon with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;tabs-are-windows&lt;/span&gt;&lt;/tt&gt; set.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;:bind &amp;lt;key&amp;gt;&lt;/tt&gt; without a command now shows the existing binding&lt;/li&gt;
&lt;li&gt;The optional &lt;tt class="docutils literal"&gt;colorlog&lt;/tt&gt; dependency got removed, as qutebrowser now displays
colored logs without it.&lt;/li&gt;
&lt;li&gt;URLs are now shown decoded when hovering.&lt;/li&gt;
&lt;li&gt;Keybindings are now shown in the command completion&lt;/li&gt;
&lt;li&gt;Improved behavior when pasting multiple lines&lt;/li&gt;
&lt;li&gt;Rapid hints can now also be used for the &lt;tt class="docutils literal"&gt;normal&lt;/tt&gt; hint target, which can be
useful with javascript click handlers or checkboxes which don't actually open
a new page.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:zoom-in&lt;/span&gt;&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:zoom-out&lt;/span&gt;&lt;/tt&gt; (&lt;tt class="docutils literal"&gt;+&lt;/tt&gt;/&lt;tt class="docutils literal"&gt;-&lt;/tt&gt;) with a too large count now zooms to the
smallest/largest zoom instead of doing nothing.&lt;/li&gt;
&lt;li&gt;The commandline now accepts partially typed commands if they're unique.&lt;/li&gt;
&lt;li&gt;Number hints are now kept filtered after following a hint in rapid mode.&lt;/li&gt;
&lt;li&gt;Number hints are now renumbered after filtering&lt;/li&gt;
&lt;li&gt;Number hints can now be filtered with multiple space-separated search terms&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;hints &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; scatter&lt;/tt&gt; is now ignored for number hints&lt;/li&gt;
&lt;li&gt;Better history implementation which also stores titles.
As a consequence, URLs which redirect to another URL are now added to the
history too, marked with a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-r&lt;/span&gt;&lt;/tt&gt; suffix to the timestamp field.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="fixed"&gt;
&lt;h2&gt;Fixed&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Fixed using &lt;tt class="docutils literal"&gt;:hint links spawn&lt;/tt&gt; with flags - you can now use things like the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-v&lt;/span&gt;&lt;/tt&gt; argument for &lt;tt class="docutils literal"&gt;:spawn&lt;/tt&gt; or pass flags to the spawned commands.&lt;/li&gt;
&lt;li&gt;Various fixes for hinting corner-cases where following a link didn't work or
the hint was drawn at the wrong position.&lt;/li&gt;
&lt;li&gt;Fixed crash when downloading from an URL with SSL errors&lt;/li&gt;
&lt;li&gt;Close file handles correctly when a download failed&lt;/li&gt;
&lt;li&gt;Fixed crash when using &lt;tt class="docutils literal"&gt;;Y&lt;/tt&gt; (&lt;tt class="docutils literal"&gt;:hint links &lt;span class="pre"&gt;yank-primary&lt;/span&gt;&lt;/tt&gt;) on a system without
primary selection&lt;/li&gt;
&lt;li&gt;Don't display quit confirmation with finished downloads&lt;/li&gt;
&lt;li&gt;Fixed updating the tab index in the statusbar when opening a background tab&lt;/li&gt;
&lt;li&gt;Fixed a crash when entering &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:--&lt;/span&gt;&lt;/tt&gt; in the commandline&lt;/li&gt;
&lt;li&gt;Fixed &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:debug-console&lt;/span&gt;&lt;/tt&gt; with PyQt 5.6&lt;/li&gt;
&lt;li&gt;Fixed qutebrowser not starting when &lt;tt class="docutils literal"&gt;sys.stderr&lt;/tt&gt; is &lt;tt class="docutils literal"&gt;None&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Fixed crash when cancelling a download which belongs to a MHTML download&lt;/li&gt;
&lt;li&gt;Fixed rebinding of keybindings being case-sensitive&lt;/li&gt;
&lt;li&gt;Fix for tab indicators getting lost when moving tabs&lt;/li&gt;
&lt;li&gt;Fixed handling of backspace in number hinting mode&lt;/li&gt;
&lt;li&gt;Fixed &lt;tt class="docutils literal"&gt;FileNotFoundError&lt;/tt&gt; when starting in some cases on old Qt versions&lt;/li&gt;
&lt;li&gt;Fixed sharing of cookies between tabs when &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;private-browsing&lt;/span&gt;&lt;/tt&gt; is enabled&lt;/li&gt;
&lt;li&gt;Toggling values with &lt;tt class="docutils literal"&gt;:set&lt;/tt&gt; now uses lower-case values&lt;/li&gt;
&lt;li&gt;Hints now work with (non-standard) links with spaces around the URL&lt;/li&gt;
&lt;li&gt;Strip off trailing spaces for history entries with no title&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since v0.6.0, the following people have contributed to qutebrowser:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Ryan Roden-Corrent&lt;/li&gt;
&lt;li&gt;Daniel Schadt&lt;/li&gt;
&lt;li&gt;Jakub Klinkovsk&lt;/li&gt;
&lt;li&gt;Panagiotis Ktistakis&lt;/li&gt;
&lt;li&gt;Corentin Jul&lt;/li&gt;
&lt;li&gt;Felix Van der Jeugt&lt;/li&gt;
&lt;li&gt;Tarcisio Fedrizzi&lt;/li&gt;
&lt;li&gt;Liam BEGUIN&lt;/li&gt;
&lt;li&gt;Jimmy&lt;/li&gt;
&lt;li&gt;kanikaa1234&lt;/li&gt;
&lt;li&gt;Tomasz Kramkowski&lt;/li&gt;
&lt;li&gt;Philipp Hansch&lt;/li&gt;
&lt;li&gt;Nick Ginther&lt;/li&gt;
&lt;li&gt;Fritz Reichwald&lt;/li&gt;
&lt;li&gt;haitaka&lt;/li&gt;
&lt;li&gt;Ismail&lt;/li&gt;
&lt;li&gt;adam&lt;/li&gt;
&lt;li&gt;Stefan Tatschner&lt;/li&gt;
&lt;li&gt;Samuel Loury&lt;/li&gt;
&lt;li&gt;Jan Verbeek&lt;/li&gt;
&lt;li&gt;oniondreams&lt;/li&gt;
&lt;li&gt;Xitian9&lt;/li&gt;
&lt;li&gt;Noah Huesser&lt;/li&gt;
&lt;li&gt;Johannes Martinsson&lt;/li&gt;
&lt;li&gt;Jay Kamat&lt;/li&gt;
&lt;li&gt;Error 800&lt;/li&gt;
&lt;li&gt;Alexey Glushko&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thank you!&lt;/p&gt;
&lt;/div&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category></entry><entry><title>Day 4: Playing whack-a-mole</title><link href="https://blog.qutebrowser.org/day-4-playing-whack-a-mole.html" rel="alternate"></link><published>2016-06-09T23:04:19+02:00</published><updated>2016-07-12T11:15:37+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-06-09:/day-4-playing-whack-a-mole.html</id><summary type="html">&lt;p&gt;Today, I felt like I was forced to play whack-a-mole:&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="whack-a-mole" src="/images/mole.png" /&gt;
&lt;p class="caption"&gt;(Image cc by-nc-sa by &lt;a class="reference external" href="https://www.flickr.com/photos/mommysaurus75/5518643830/"&gt;Mommysaurus75&lt;/a&gt; on Flickr)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-good"&gt;
&lt;h2&gt;The good&lt;/h2&gt;
&lt;p&gt;Everything started nicely: Someone posted a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1564"&gt;pull request&lt;/a&gt; to handle links
with (non-standard) spaces correctly with hints
(&lt;tt class="docutils literal"&gt;&amp;lt;a href=&amp;quot; &lt;span class="pre"&gt;http://example.com&lt;/span&gt; &amp;quot;&amp;gt;&lt;/tt&gt;), I told them how to add a test, they …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Today, I felt like I was forced to play whack-a-mole:&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="whack-a-mole" src="/images/mole.png" /&gt;
&lt;p class="caption"&gt;(Image cc by-nc-sa by &lt;a class="reference external" href="https://www.flickr.com/photos/mommysaurus75/5518643830/"&gt;Mommysaurus75&lt;/a&gt; on Flickr)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-good"&gt;
&lt;h2&gt;The good&lt;/h2&gt;
&lt;p&gt;Everything started nicely: Someone posted a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1564"&gt;pull request&lt;/a&gt; to handle links
with (non-standard) spaces correctly with hints
(&lt;tt class="docutils literal"&gt;&amp;lt;a href=&amp;quot; &lt;span class="pre"&gt;http://example.com&lt;/span&gt; &amp;quot;&amp;gt;&lt;/tt&gt;), I told them how to add a test, they did,
I fixed a small issue, bam, merged.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-bad"&gt;
&lt;h2&gt;The bad&lt;/h2&gt;
&lt;p&gt;Then I fixed some tests which were failing due to changes from yesterday. The
first one was a test which failed reliably on Windows since changing the test
to use a real file instead of a mock.&lt;/p&gt;
&lt;p&gt;It tests a function getting the last &lt;strong&gt;n&lt;/strong&gt; bytes from a file, with 64 bytes.
On Windows, it expected:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt; 58&lt;/span&gt;
&lt;span class="err"&gt;new data 59&lt;/span&gt;
&lt;span class="err"&gt;new data 60&lt;/span&gt;
&lt;span class="err"&gt;new data 61&lt;/span&gt;
&lt;span class="err"&gt;new data 62&lt;/span&gt;
&lt;span class="err"&gt;new data 63&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;but got:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;ew data 59&lt;/span&gt;
&lt;span class="err"&gt;new data 60&lt;/span&gt;
&lt;span class="err"&gt;new data 61&lt;/span&gt;
&lt;span class="err"&gt;new data 62&lt;/span&gt;
&lt;span class="err"&gt;new data 63&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unfortunately pytest failed to produce a nice readable diff like it usually
does:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; assert lineparser.get_recent(size) == data&lt;/span&gt;
&lt;span class="err"&gt;E assert [&amp;#39;ew data 59\...ew data 63\n&amp;#39;] ==&lt;/span&gt;
&lt;span class="err"&gt;         [&amp;#39; 58\n&amp;#39;, &amp;#39;new...ew data 63\n&amp;#39;]&lt;/span&gt;
&lt;span class="err"&gt;E   At index 0 diff: &amp;#39;ew data 59\n&amp;#39; != &amp;#39; 58\n&amp;#39;&lt;/span&gt;
&lt;span class="err"&gt;E   Right contains more items, first extra item: &amp;#39;new data 63\n&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After printing the raw values staring at them for some seconds, I figured the
few missing bytes were exactly the count of &lt;tt class="docutils literal"&gt;\r&lt;/tt&gt; (carriage returns) you'd
need to insert.&lt;/p&gt;
&lt;p&gt;While Python takes care of the conversion when reading/writing files, when
getting the last 64 bytes of a file, you'll get less data on Windows.&lt;/p&gt;
&lt;p&gt;I fixed the code to use &lt;tt class="docutils literal"&gt;os.linesep&lt;/tt&gt; instead of &lt;tt class="docutils literal"&gt;\n&lt;/tt&gt;, and it still was off
by one on Windows, but not in Linux:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# data = &amp;#39;\n&amp;#39;.join(self.BASE_DATA + new_data)&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linesep&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BASE_DATA&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;new_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then figured out I actually had an off-by-one error there - the
&amp;quot;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-(size&lt;/span&gt; - 1)&lt;/tt&gt;&amp;quot; should actually be just &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-size&lt;/span&gt;&lt;/tt&gt;. What I &lt;strong&gt;actually&lt;/strong&gt; was
missing is a &amp;quot;&lt;tt class="docutils literal"&gt;+ os.linesep&lt;/tt&gt;&amp;quot; for the final line ending. I guess when
originally implemented it I thought I just was off by one while &lt;a class="reference external" href="http://stackoverflow.com/a/509295/2085149"&gt;slicing&lt;/a&gt; and
naively fixed it the wrong way...&lt;/p&gt;
&lt;p&gt;With that &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/d6926f06227616c0f659ff1f39ec84f0e9b67465"&gt;out of the way&lt;/a&gt;, I looked at the other test which was flaky - it
reads the history a qutebrowser subprocess, definitely waits until the
subprocess has written it, and still sometimes ends up with an empty file.&lt;/p&gt;
&lt;p&gt;I let the logs sink in for a bit, but I still have no idea what'd cause it. In
the end I just ended up &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/9e1d20017c6e7a59083d1a2bc1af0e4710b0ffb2"&gt;marking&lt;/a&gt; the test as flaky using
&lt;a class="reference external" href="https://github.com/pytest-dev/pytest-rerunfailures"&gt;pytest-rerunfailures&lt;/a&gt;. This means it'll be run a second time if it fails, and
if it passes then, it's assumed to be okay.&lt;/p&gt;
&lt;p&gt;This is definitely less than ideal, but it's better than having a test which
fails sometimes for no apparent reason, and better than not testing this
functionality at all.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-ugly"&gt;
&lt;h2&gt;The ugly&lt;/h2&gt;
&lt;p&gt;After all that, I updated to Qt 5.6.1 to check if a &lt;a class="reference external" href="https://bugreports.qt.io/browse/QTBUG-52988"&gt;segfault on exit&lt;/a&gt; was
fixed like claimed in the bug report.&lt;/p&gt;
&lt;p&gt;Turns out it wasn't, but instead there was a new &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/c390c797b2de96b18db21eb3cdcf7829a6220598"&gt;bogus warning&lt;/a&gt; and a
&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/2d54c927e34abaead2366aeac5465da400b1a9f4"&gt;weird behavior change&lt;/a&gt; I needed to take care of in my testsuite.&lt;/p&gt;
&lt;p&gt;Now I hoped I was finally done fixing weird bugs - turns out that was just the
beginning. Someone joined the IRC channel and reported how hints often don't
work at all for them since the big hint changes from Monday.&lt;/p&gt;
&lt;p&gt;I couldn't reproduce the issue, and what we were seeing made no sense at all.
See the &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/1568"&gt;bug report&lt;/a&gt; I opened to see all the gory details. If I tried to write
them up here, I'd probably just hopelessly confuse myself again.&lt;/p&gt;
&lt;p&gt;They are an experienced Python programmer as well, and after over 3.5h of
debugging, we gave up.&lt;/p&gt;
&lt;p&gt;I ended up &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/035526848eb40cb95f70926667911f5bc5f8e393"&gt;adding a setting&lt;/a&gt; which allows to revert back to the old Python
implementation. It's less accurate but also faster than the new (JS) one, so
some people might prefer that anyways.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="and-some-other-changes"&gt;
&lt;h2&gt;And some other changes&lt;/h2&gt;
&lt;p&gt;Before and after that frustrating debugging session, I also managed to get some
other changes in:&lt;/p&gt;
&lt;p&gt;I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/089131c79dbc069c5c5ce30f70b4392d1bd7d80a"&gt;improved the error message&lt;/a&gt; when an invalid link is clicked as I stumbled
upon it and it confused me.&lt;/p&gt;
&lt;p&gt;I also &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/compare/34ba44b0a31272c93517be422f91684c39221205~1...14a04f1535f8e8df5813b8d7b3b4420650e5400b"&gt;started refactoring&lt;/a&gt; the history implementation and adding a few tests
to it, as I still need to do a small change to handle redirects nicely before
releasing v0.7.0 (what is what I originally planned to do today...).&lt;/p&gt;
&lt;p&gt;The refactoring also allowed me to split off the QtWebKit-specific part of it
nicely, so that's already a little step closer to QtWebEngine as a nice side
effect!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="outlook"&gt;
&lt;h2&gt;Outlook&lt;/h2&gt;
&lt;p&gt;The todo list for tomorrow roughly looks like this:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Handle redirects in saved history&lt;/li&gt;
&lt;li&gt;Merge the trivial doc PR for the Debian packages&lt;/li&gt;
&lt;li&gt;Package and release v0.7.0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I really want to release v0.7.0 tomorrow unless another serious regression is
found (fingers crossed!).&lt;/p&gt;
&lt;p&gt;And then full-speed towards QtWebEngine support next week!&lt;/p&gt;
&lt;/div&gt;
</content><category term="pytest"></category></entry><entry><title>Day 3: Last pull requests and managing requirement files</title><link href="https://blog.qutebrowser.org/day-3-last-pull-requests-and-managing-requirement-files.html" rel="alternate"></link><published>2016-06-09T00:22:21+02:00</published><updated>2016-06-09T00:22:21+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-06-09:/day-3-last-pull-requests-and-managing-requirement-files.html</id><summary type="html">&lt;div class="section" id="managing-requirement-files"&gt;
&lt;h2&gt;Managing requirement files&lt;/h2&gt;
&lt;p&gt;Yesterday evening, I got side-tracked with another &amp;quot;small&amp;quot; side project which
turned out to be a bit bigger.&lt;/p&gt;
&lt;p&gt;qutebrowser comes with &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/tree/master/misc/requirements"&gt;requirement files&lt;/a&gt; which &lt;a class="reference external" href="http://nvie.com/posts/pin-your-packages/"&gt;pin all dependencies&lt;/a&gt; for
the automated tests and other tasks (like linters).&lt;/p&gt;
&lt;p&gt;This includes indirect dependencies to make sure builds are reproducible. For …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="section" id="managing-requirement-files"&gt;
&lt;h2&gt;Managing requirement files&lt;/h2&gt;
&lt;p&gt;Yesterday evening, I got side-tracked with another &amp;quot;small&amp;quot; side project which
turned out to be a bit bigger.&lt;/p&gt;
&lt;p&gt;qutebrowser comes with &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/tree/master/misc/requirements"&gt;requirement files&lt;/a&gt; which &lt;a class="reference external" href="http://nvie.com/posts/pin-your-packages/"&gt;pin all dependencies&lt;/a&gt; for
the automated tests and other tasks (like linters).&lt;/p&gt;
&lt;p&gt;This includes indirect dependencies to make sure builds are reproducible. For
example, the requirement file used to install &lt;a class="reference external" href="https://testrun.org/tox/latest/"&gt;tox&lt;/a&gt; in the build images looks
like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;pluggy==0.3.1&lt;/span&gt;
&lt;span class="err"&gt;py==1.4.31&lt;/span&gt;
&lt;span class="err"&gt;tox==2.3.1&lt;/span&gt;
&lt;span class="err"&gt;virtualenv==15.0.2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now for larger requirement files, this gets quite cumbersome. While version
updates are easy thanks to &lt;a class="reference external" href="https://requires.io/"&gt;requires.io&lt;/a&gt;, it's easy to miss a new dependency
(which then isn't explicitly pinned, but silently works) or a removed one.&lt;/p&gt;
&lt;p&gt;It'd be preferrable to have a file with &amp;quot;loose&amp;quot; dependencies (so just &lt;tt class="docutils literal"&gt;tox&lt;/tt&gt;
in this case), and then generate the above file from that.&lt;/p&gt;
&lt;p&gt;One existing solution for this problem is &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pip-compile&lt;/span&gt;&lt;/tt&gt;, part of
&lt;a class="reference external" href="https://github.com/nvie/pip-tools"&gt;pip-tools&lt;/a&gt;. That's what I initially tried using, but I noticed various
issues:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;It didn't work with the local paths (requirements inside the qutebrowser
repo) I need for pylint.&lt;/li&gt;
&lt;li&gt;It required some options for git requirements I didn't really agree with.&lt;/li&gt;
&lt;li&gt;It doesn't support &amp;quot;blacklisting&amp;quot; a requirement which should be excluded from
the compiled file.&lt;/li&gt;
&lt;li&gt;It doesn't support adding comments to the generated file, which I'd need for
requires.io.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Inspired by a &lt;a class="reference external" href="http://www.kennethreitz.org/essays/a-better-pip-workflow"&gt;blog post&lt;/a&gt; by &lt;a class="reference external" href="http://www.kennethreitz.org/"&gt;Kenneth Reitz&lt;/a&gt;, I noticed generating such a
&amp;quot;compiled&amp;quot; requirements file could be much easier:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ virtualenv venv
$ ./venv/bin/pip install -r requirements.txt-raw
$ ./venv/bin/pip freeze &amp;gt; requirements.txt
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then wrote a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/blob/master/scripts/dev/recompile_requirements.py"&gt;small script&lt;/a&gt; which does that for all requirement files. The
output looked like what I expected, except for some small differences:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The commit ID was pinned for git requirements, which I didn't want in this
case (as I have an environment to try the newest pylint/astroid).&lt;/li&gt;
&lt;li&gt;The local file path (&lt;tt class="docutils literal"&gt;./scripts/dev/pylint_checkers&lt;/tt&gt;) got replaced by its
package name (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;qute-pylint&lt;/span&gt;&lt;/tt&gt;).&lt;/li&gt;
&lt;li&gt;I still needed a way to ignore some dependencies and to add comment to the
output.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After a bit of thinking, I came up with four special comments (starting with
&lt;tt class="docutils literal"&gt;#&amp;#64;&lt;/tt&gt;) you could put in a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;requirements.raw-txt&lt;/span&gt;&lt;/tt&gt;:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&amp;quot;&lt;tt class="docutils literal"&gt;#&amp;#64; comment: mypkg blah blub&lt;/tt&gt;&amp;quot; to add a comment for &lt;tt class="docutils literal"&gt;mypkg&lt;/tt&gt; in the output&lt;/li&gt;
&lt;li&gt;&amp;quot;&lt;tt class="docutils literal"&gt;#&amp;#64; filter: mypkg != 1.0.0&lt;/tt&gt;&amp;quot; as shorthand to add a &lt;tt class="docutils literal"&gt;# rq.filter: ...&lt;/tt&gt; comment for requires.io&lt;/li&gt;
&lt;li&gt;&amp;quot;&lt;tt class="docutils literal"&gt;#&amp;#64; ignore: mypkg, otherpkg&lt;/tt&gt;&amp;quot; to not add the given packages to the output&lt;/li&gt;
&lt;li&gt;&amp;quot;&lt;tt class="docutils literal"&gt;#&amp;#64; replace: foo bar&lt;/tt&gt;&amp;quot; to replace a line in the output&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This worked out really well. I could now have an input like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;beautifulsoup4&lt;/span&gt;
&lt;span class="err"&gt;CherryPy&lt;/span&gt;
&lt;span class="err"&gt;coverage&lt;/span&gt;
&lt;span class="err"&gt;Flask==0.10.1&lt;/span&gt;
&lt;span class="err"&gt;httpbin&lt;/span&gt;
&lt;span class="err"&gt;...&lt;/span&gt;

&lt;span class="err"&gt;#@ filter: Flask &amp;lt; 0.11.0&lt;/span&gt;
&lt;span class="err"&gt;#@ ignore: Jinja2, MarkupSafe&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And get this as output:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;# This file is automatically generated by recompile_requirements.py&lt;/span&gt;

&lt;span class="err"&gt;beautifulsoup4==4.4.1&lt;/span&gt;
&lt;span class="err"&gt;CherryPy==6.0.1&lt;/span&gt;
&lt;span class="err"&gt;coverage==4.1&lt;/span&gt;
&lt;span class="err"&gt;decorator==4.0.10&lt;/span&gt;
&lt;span class="err"&gt;Flask==0.10.1  # rq.filter: &amp;lt; 0.11.0&lt;/span&gt;
&lt;span class="err"&gt;glob2==0.4.1&lt;/span&gt;
&lt;span class="err"&gt;httpbin==0.4.1&lt;/span&gt;
&lt;span class="err"&gt;hypothesis==3.4.0&lt;/span&gt;
&lt;span class="err"&gt;itsdangerous==0.24&lt;/span&gt;
&lt;span class="err"&gt;# Jinja2==2.8&lt;/span&gt;
&lt;span class="err"&gt;Mako==1.0.4&lt;/span&gt;
&lt;span class="err"&gt;# MarkupSafe==0.23&lt;/span&gt;
&lt;span class="err"&gt;parse==1.6.6&lt;/span&gt;
&lt;span class="err"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This was a bit more work than I initially thought (start using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pip-compile&lt;/span&gt;&lt;/tt&gt;
and be done with it), but was interesting and worth it!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="merging-more-prs"&gt;
&lt;h2&gt;Merging more PRs&lt;/h2&gt;
&lt;p&gt;Today I was able to get in three more PRs:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1264"&gt;#1264&lt;/a&gt; adding a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:history-clear&lt;/span&gt;&lt;/tt&gt; command.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1350"&gt;#1350&lt;/a&gt; improving the page history and adding titles to the completion.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1562"&gt;#1562&lt;/a&gt; making toggling with &lt;tt class="docutils literal"&gt;:set&lt;/tt&gt; use lower-case &lt;tt class="docutils literal"&gt;true&lt;/tt&gt;/&lt;tt class="docutils literal"&gt;false&lt;/tt&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also fixed some small issues I encountered (or was reminded of) while
developing:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Using the private browsing mode didn't share cookies between tabs, which it
now does.&lt;/li&gt;
&lt;li&gt;Using &lt;tt class="docutils literal"&gt;:restart&lt;/tt&gt; crashed when there were broken symlinks around.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="outlook"&gt;
&lt;h2&gt;Outlook&lt;/h2&gt;
&lt;p&gt;The todo list for tomorrow roughly looks like this:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Fix a test added today which fails on Windows&lt;/li&gt;
&lt;li&gt;Decide &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/1345#issuecomment-224598579"&gt;what to do&lt;/a&gt; with redirected URLs in the history&lt;/li&gt;
&lt;li&gt;Merge the trivial doc PR for the Debian packages&lt;/li&gt;
&lt;li&gt;Package and release v0.7.0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So from how things are looking like now, I'll be able to start refactoring
things for QtWebEngine on Friday.&lt;/p&gt;
&lt;/div&gt;
</content><category term="pyplanet"></category></entry><entry><title>Day 2: More pull requests and nicer test output</title><link href="https://blog.qutebrowser.org/day-2-more-pull-requests-and-nicer-test-output.html" rel="alternate"></link><published>2016-06-07T19:18:07+02:00</published><updated>2016-07-12T11:15:37+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-06-07:/day-2-more-pull-requests-and-nicer-test-output.html</id><summary type="html">&lt;div class="section" id="better-bdd-output"&gt;
&lt;h2&gt;Better BDD output&lt;/h2&gt;
&lt;p&gt;Yesterday evening, a contributor had a nice &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1552#issuecomment-224047282"&gt;idea&lt;/a&gt; of a better output for
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Behavior_Driven_Development"&gt;BDD&lt;/a&gt; style tests when they fail.&lt;/p&gt;
&lt;p&gt;qutebrowser tests a lot of functionality using end-to-end tests which are
written using the &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Gherkin_(software)"&gt;Gherkin&lt;/a&gt; language with the &lt;a class="reference external" href="https://github.com/pytest-dev/pytest-bdd"&gt;pytest-bdd&lt;/a&gt; plugin. Those look
like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;Scenario:&lt;/span&gt;&lt;span class="nf"&gt; Going back without …&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="section" id="better-bdd-output"&gt;
&lt;h2&gt;Better BDD output&lt;/h2&gt;
&lt;p&gt;Yesterday evening, a contributor had a nice &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1552#issuecomment-224047282"&gt;idea&lt;/a&gt; of a better output for
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Behavior_Driven_Development"&gt;BDD&lt;/a&gt; style tests when they fail.&lt;/p&gt;
&lt;p&gt;qutebrowser tests a lot of functionality using end-to-end tests which are
written using the &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Gherkin_(software)"&gt;Gherkin&lt;/a&gt; language with the &lt;a class="reference external" href="https://github.com/pytest-dev/pytest-bdd"&gt;pytest-bdd&lt;/a&gt; plugin. Those look
like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;Scenario:&lt;/span&gt;&lt;span class="nf"&gt; Going back without history&lt;/span&gt;
&lt;span class="k"&gt;    Given &lt;/span&gt;&lt;span class="nf"&gt;I open data/backforward/&lt;/span&gt;&lt;span class="s"&gt;1.&lt;/span&gt;&lt;span class="nf"&gt;txt&lt;/span&gt;
&lt;span class="nf"&gt;    &lt;/span&gt;&lt;span class="k"&gt;When &lt;/span&gt;&lt;span class="nf"&gt;I run :back&lt;/span&gt;
&lt;span class="nf"&gt;    &lt;/span&gt;&lt;span class="k"&gt;Then &lt;/span&gt;&lt;span class="nf"&gt;the error &amp;quot;&lt;/span&gt;&lt;span class="s"&gt;At beginning of history.&lt;/span&gt;&lt;span class="nf"&gt;&amp;quot; should be shown&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;BDD tests work by spawning a local webserver, spawning a qutebrowser process,
sending commands to it, and parsing its log.&lt;/p&gt;
&lt;p&gt;If such a scenario fails however, you only can see what failed in the
underlying python code. I improved the output to add this:&lt;/p&gt;
&lt;img alt="improved BDD output" src="/images/bdd.png" /&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pytest-bdd&lt;/span&gt;&lt;/tt&gt; made this easy by adding a &lt;tt class="docutils literal"&gt;scenario&lt;/tt&gt; attribute to pytest's
&lt;a class="reference external" href="http://pytest.org/latest/writing_plugins.html#_pytest.runner.TestReport"&gt;TestReport&lt;/a&gt; object:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Pdb&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;pp&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scenario&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;examples&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="s1"&gt;&amp;#39;feature&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="s1"&gt;&amp;#39;description&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s1"&gt;&amp;#39;filename&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/home/me/.../tests/end2end/features/misc.feature&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s1"&gt;&amp;#39;line_number&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Various utility commands.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s1"&gt;&amp;#39;rel_filename&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;features/misc.feature&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s1"&gt;&amp;#39;tags&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="s1"&gt;&amp;#39;line_number&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;367&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Focusing download widget via Tab (original issue)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="s1"&gt;&amp;#39;steps&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
               &lt;span class="s1"&gt;&amp;#39;duration&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.05486869812011719&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s1"&gt;&amp;#39;failed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s1"&gt;&amp;#39;keyword&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;When&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s1"&gt;&amp;#39;line_number&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;368&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;I open data/prompt/jsprompt.html&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;when&amp;#39;&lt;/span&gt;
           &lt;span class="p"&gt;},&lt;/span&gt;
           &lt;span class="o"&gt;...&lt;/span&gt;
 &lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="s1"&gt;&amp;#39;tags&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pyqt531_or_newer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using pytest's &lt;a class="reference external" href="http://pytest.org/latest/writing_plugins.html"&gt;hook system&lt;/a&gt;, all I needed to do is adding this to my
&lt;tt class="docutils literal"&gt;conftest.py&lt;/tt&gt; (with colorizing code removed to simplify things a bit, see
the &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/blob/master/tests/end2end/features/conftest.py"&gt;full code&lt;/a&gt; for details):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nd"&gt;@pytest.hookimpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hookwrapper&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pytest_runtest_makereport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Add a BDD section to the test output.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;outcome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;call&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;teardown&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;longrepr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;addsection&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt;
            &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;scenario&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Feature: {name}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scenario&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;feature&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;  Scenario: {name} ({filename}:{line})&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scenario&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scenario&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;feature&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;rel_filename&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scenario&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;line_number&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scenario&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;steps&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;    {keyword} {name} ({duration:.2f}s)&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;keyword&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;duration&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;longrepr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addsection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;BDD scenario&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="hinting-improvements"&gt;
&lt;h2&gt;Hinting improvements&lt;/h2&gt;
&lt;p&gt;Today I was mostly busy with merging a half-year old &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1194"&gt;pull request&lt;/a&gt; with
various hint improvements which was missing tests, and the author of it didn't
have the time to add them currently.&lt;/p&gt;
&lt;p&gt;To make things easier, I reviewed and cherry-picked the individual commits one
by one, and then added tests for them. See the &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/compare/b759f481c4ca242451e8f6539e6d594c9c07295c...b972acf20c5d4b9ad0f03adfdb8af2f1300bac51"&gt;resulting merge&lt;/a&gt; if you're
curious.&lt;/p&gt;
&lt;p&gt;This improves a variety of things related to hinting, most of them when using
number hints:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;New &lt;cite&gt;hints -&amp;gt; auto-follow-timeout&lt;/cite&gt; setting to ignore keypresses after
following a hint when filtering in number mode.&lt;/li&gt;
&lt;li&gt;Number hints are now kept filtered after following a hint in rapid mode.&lt;/li&gt;
&lt;li&gt;Number hints are now renumbered after filtering&lt;/li&gt;
&lt;li&gt;Number hints can now be filtered with multiple space-separated search terms&lt;/li&gt;
&lt;li&gt;&lt;cite&gt;hints -&amp;gt; scatter&lt;/cite&gt; is now ignored for number hints&lt;/li&gt;
&lt;li&gt;Fixed handling of backspace in number hinting mode&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Currently it's looking like I have three pull requests left to merge tomorrow,
one of them being a trivial doc update about Debian packages which is ready to
merge, but I'll merge it shortly before the release.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="other-fixes"&gt;
&lt;h2&gt;Other fixes&lt;/h2&gt;
&lt;p&gt;I also pushed two other small fixes today:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/e8123bb68ac019deab7ff32223ae3214323dd31c"&gt;A fix for parsing newer pdfjs version numbers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/9880f5bd5f94498b233539c6c9588225c10b77bc"&gt;A fix for FileNotFoundError sometimes being raised on start with older Qt versions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="pytest"></category></entry><entry><title>Day 1: Merging pull requests, and a stupid bug</title><link href="https://blog.qutebrowser.org/day-1-merging-pull-requests-and-a-stupid-bug.html" rel="alternate"></link><published>2016-06-06T20:47:30+02:00</published><updated>2016-06-06T20:47:30+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-06-06:/day-1-merging-pull-requests-and-a-stupid-bug.html</id><summary type="html">&lt;p&gt;Today was my first day of working on QtWebEngine, and as mentioned in the
previous post I started with merging some pull requests before they diverge too
much because of all the planned refactoring.&lt;/p&gt;
&lt;p&gt;In the morning I was in the train without an internet connection, so I worked
on …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Today was my first day of working on QtWebEngine, and as mentioned in the
previous post I started with merging some pull requests before they diverge too
much because of all the planned refactoring.&lt;/p&gt;
&lt;p&gt;In the morning I was in the train without an internet connection, so I worked
on adding a few missing tests:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/3cfb430cdfddb8c0298e091558a7d59cfa5d1521"&gt;Spawning external editor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Some &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/tree/master/tests/manual/hints"&gt;test pages&lt;/a&gt;
for manual inspection for hint rendering, as that's difficult to automate.
For some of those I attemted to create minimal examples but failed, if you
know your way around HTML/CSS your help would be appreciated! See &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/1550"&gt;#1550&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I then &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/b1914d641437c80e2cc17ae8fd44edba58b5851c"&gt;merged&lt;/a&gt;
a pretty old pull request helping with hints positioning in some corner cases,
where those tests really helped.&lt;/p&gt;
&lt;p&gt;After doing so I cleaned up the current &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/blob/master/qutebrowser/browser/webelem.py"&gt;webelem&lt;/a&gt;
code a bit (which will also help when porting hints to QtWebEngine) and really
confused myself with zoom adjustments for hints.&lt;/p&gt;
&lt;p&gt;When drawing hints, the coordinates need to be adjusted &amp;quot;negatively&amp;quot; for the
zoom level of the web view, so that the hint gets clicked with the correct
position.&lt;/p&gt;
&lt;p&gt;When getting the element coordinates via javascript however (like the PR did if
possible), they are already adjusted accordingly. Since the code
&lt;strong&gt;drawing&lt;/strong&gt; the hints needs the unadjusted position, the zoom level needs to be
adjusted in the other direction.&lt;/p&gt;
&lt;p&gt;To top off the confusion, in the unit tests I'm not actually getting the
element position via javascript, so I had to adjust the coordinates a third
time so the fake &lt;tt class="docutils literal"&gt;getElementRects()&lt;/tt&gt; method would act like in real-life.&lt;/p&gt;
&lt;p&gt;After doing so, some tests failed with a strange error - the position of the
rectangles was adjusted, but the width and height was not:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;QRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;QRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After a lot of head-scratching, I found the culprit:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;left&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;scroll_x&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;top&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;scroll_y&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;right&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;scroll_x&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;bottom&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;scroll_y&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;width&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;height&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This was fixed by adding the needed parentheses:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;left&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;scroll_x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;top&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;scroll_y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;right&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;scroll_x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;bottom&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;scroll_y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;width&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;height&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In hindsight it's - as always - totally obvious, but it was a nightmare to
debug.&lt;/p&gt;
&lt;p&gt;Since those tests (checking if zoom was accounted for properly) used a scroll
position of 0/0, this evaluated to &lt;tt class="docutils literal"&gt;geometry.left() - (0 / zoom)&lt;/tt&gt; which is
&lt;tt class="docutils literal"&gt;geometry.left()&lt;/tt&gt;. The width and height were correct because they didn't
subtract any scroll position...&lt;/p&gt;
&lt;p&gt;But the frustration was worth it, hints are now drawn correctly in various
corner cases!&lt;/p&gt;
&lt;p&gt;After that, I merged and closed some more pull requests:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/abfd789f9e310daff9f042fe432975ea082cd862"&gt;improved&lt;/a&gt;
how zooming behaves with a too big count and thus superseded/closed &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1140"&gt;#1140&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I picked out a &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/3e22f64a20a52004d1927829b9cc31f5d6b3dcde"&gt;fix&lt;/a&gt;
for tab indicators disappearing when using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:tab-move&lt;/span&gt;&lt;/tt&gt;, and then closed
&lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/697"&gt;#697&lt;/a&gt; (which was
pretty much a year old...) because the other things are either already fixed
in the meantime, or things I disagree with.&lt;/li&gt;
&lt;li&gt;I &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/commit/57a1847e3a1d18cfdf60c627e04cb66c88d29167"&gt;added&lt;/a&gt;
some missing bits and tests for &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pull/1460"&gt;#1460&lt;/a&gt;
which allows to use partial commands (like &lt;tt class="docutils literal"&gt;:bac&lt;/tt&gt;) if they're unique in the command bar.&lt;/li&gt;
&lt;li&gt;And some other bits and bytes like updating pinned test dependencies or
removing a few lines unused code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, only 10 pull requests are &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pulls"&gt;still open&lt;/a&gt;,
of which two are work-in-progress, and four are explicitly marked as postponed
until after QtWebEngine support.&lt;/p&gt;
&lt;p&gt;I plan to merge the other 6 pull requests and release a v0.7 over the next
day(s), and then all is ready to start! \o/&lt;/p&gt;
</content></entry><entry><title>About and Timeline</title><link href="https://blog.qutebrowser.org/about-and-timeline.html" rel="alternate"></link><published>2016-06-05T13:08:59+02:00</published><updated>2016-06-06T10:10:07+02:00</updated><author><name>Florian Bruhin</name></author><id>tag:blog.qutebrowser.org,2016-06-05:/about-and-timeline.html</id><summary type="html">&lt;div class="section" id="introduction"&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;A bit over two months ago, I started a &lt;a class="reference external" href="http://igg.me/at/qutebrowser"&gt;crowdfunding campaign&lt;/a&gt; for
&lt;a class="reference external" href="http://www.qutebrowser.org/"&gt;qutebrowser&lt;/a&gt;, with the goal of working full-time on adding &lt;a class="reference external" href="http://doc.qt.io/qt-5/qtwebengine-index.html"&gt;QtWebEngine&lt;/a&gt;
support to it, which will bring more stability, security and features.&lt;/p&gt;
&lt;p&gt;I asked for 3000€ to fund a month of full-time work before starting my studies
in …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="section" id="introduction"&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;A bit over two months ago, I started a &lt;a class="reference external" href="http://igg.me/at/qutebrowser"&gt;crowdfunding campaign&lt;/a&gt; for
&lt;a class="reference external" href="http://www.qutebrowser.org/"&gt;qutebrowser&lt;/a&gt;, with the goal of working full-time on adding &lt;a class="reference external" href="http://doc.qt.io/qt-5/qtwebengine-index.html"&gt;QtWebEngine&lt;/a&gt;
support to it, which will bring more stability, security and features.&lt;/p&gt;
&lt;p&gt;I asked for 3000€ to fund a month of full-time work before starting my studies
in September. The campaign took off more than I'd have ever imagined and was
almost funded in the first 24h.&lt;/p&gt;
&lt;p&gt;At the end of the campaign, I got two months of full-time work funded. I'm now
close to starting those awesome two months and set up this blog as a work log
for what I'm doing, inspired by the one of &lt;a class="reference external" href="http://git-annex.branchable.com/devblog/"&gt;git annex assistant&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also submitted this blog to &lt;a class="reference external" href="http://planetpython.org/"&gt;planet python&lt;/a&gt;,  &lt;a class="reference external" href="http://planet.pytest.org/"&gt;planet pytest&lt;/a&gt; and
&lt;a class="reference external" href="http://planet.qt.io/"&gt;planet Qt&lt;/a&gt; - if you're reading this via one of those, fear not: I have
dedicated tags for them, and only will tag posts which actually seem relevant,
so you won't see daily posts there.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="timeline"&gt;
&lt;h2&gt;Timeline&lt;/h2&gt;
&lt;p&gt;My full-time work is planned to start &lt;em&gt;tomorrow&lt;/em&gt;. I have some other obligations
until September, so there will be some days in between where I won't be working
on qutebrowser, but other things related to either Python or my studies.&lt;/p&gt;
&lt;p&gt;This is the tenative schedule:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;June 6th - 10th: &lt;strong&gt;qutebrowser (days 1-5)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;June 13th - 15th: &lt;strong&gt;qutebrowser (days 6-8)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;June 16th - 29th I'll be in &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Freiburg_im_Breisgau"&gt;Freiburg&lt;/a&gt; for the development &lt;a class="reference external" href="http://pytest.org/latest/announce/sprint2016.html"&gt;sprint&lt;/a&gt; on
&lt;a class="reference external" href="http://www.pytest.org/"&gt;pytest&lt;/a&gt; (which qutebrowser is using too), and giving a 3-day &lt;a class="reference external" href="http://www.python-academy.com/courses/specialtopics/python_course_testing.html"&gt;training&lt;/a&gt;
for it.&lt;/li&gt;
&lt;li&gt;June 30th - July 1st: &lt;strong&gt;qutebrowser (days 9-10)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;July 4th - 8th: &lt;strong&gt;qutebrowser (days 11-15)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;July 11th - 15th: &lt;strong&gt;qutebrowser (days 16-20)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;July 17th - 24th I'll be in &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Bilbao"&gt;Bilbao&lt;/a&gt; at &lt;a class="reference external" href="http://europython.eu/"&gt;EuroPython&lt;/a&gt; giving
&lt;a class="reference external" href="https://ep2016.europython.eu/conference/talks/pytest-simple-rapid-and-fun-testing-with-python-1"&gt;another training&lt;/a&gt; about pytest and hopefully learning a lot in all the
awesome talks.&lt;/li&gt;
&lt;li&gt;July 25th - 29th: &lt;strong&gt;qutebrowser (days 21-25)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;August 1st - 5th: &lt;strong&gt;qutebrowser (days 26-30)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;August 8th - 11th: &lt;strong&gt;qutebrowser (days 31-34)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;August 12th I'll be travelling to &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Cologne"&gt;Cologne&lt;/a&gt; for &lt;a class="reference external" href="http://www.evoke.eu/"&gt;Evoke&lt;/a&gt;, a &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Demoparty"&gt;demoparty&lt;/a&gt; I'm
visiting every year (let me point out this has nothing to do with political
demos, go check the wikipedia article :P).&lt;/li&gt;
&lt;li&gt;August 15th - 19th: &lt;strong&gt;qutebrowser (days 35-39)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;August 22th - September 2nd I'll be busy with a math preparation course of
the university I'll be going to.&lt;/li&gt;
&lt;li&gt;September 5th - 9th: &lt;strong&gt;qutebrowser (day 40 and some buffer)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="plans"&gt;
&lt;h2&gt;Plans&lt;/h2&gt;
&lt;p&gt;The work required to get QtWebEngine to run can roughly be divided into four
steps:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;strong&gt;Preparation:&lt;/strong&gt; Writing end-to-end tests for all important features, merging
some &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/pulls"&gt;pull requests&lt;/a&gt; which are still open, doing a last release without any
QtWebEngine support at all, and organizing/shipping t-shirts/stickers for the
crowdfunding. A lot of this already happened over the past few months, but I
still expect this to take the first few days.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Refactoring:&lt;/strong&gt; Since I plan to keep QtWebKit support for now, I'll refactor
the current code so there's a clear abstraction layer over all
backend-specific code. This will also make it easier to add support for a new
backend (say, &lt;a class="reference external" href="https://servo.org/"&gt;Servo&lt;/a&gt;) in the future. Since this will probably break a lot
in the initial phase, this work will happen in a separate branch. As soon as
the current QtWebKit backend works fine again, that'll be merged and
QtWebEngine support will be in the main branch behind a &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Feature_toggle"&gt;feature switch&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Basic browsing&lt;/strong&gt;: The next step is to get basic browsing with
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--backend&lt;/span&gt; webengine&lt;/tt&gt; working. This means you'll already be able to surf,
but things like adblocking, settings, automatic insert mode, downloads or
hints will show an error or simply not work yet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Everything else&lt;/strong&gt;: All current features which are implementable with
QtWebEngine will work, others will be clearly disabled (a few obscure
settings might be missing with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--backend&lt;/span&gt; webengine&lt;/tt&gt; for example). See the
respective &lt;a class="reference external" href="https://github.com/The-Compiler/qutebrowser/issues/666"&gt;issue&lt;/a&gt; for a breakdown of features which will probably require
some extra work.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="frequently-asked-questions"&gt;
&lt;h2&gt;Frequently asked questions&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;When will I be able to use QtWebEngine?&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;This depends on what features you need, and how fast I'll get them to work.
Estimating how long the steps outlined above will take is quite difficult, but I
hope you'll have something to try after the first week or so.&lt;/p&gt;
&lt;p&gt;Also note you'll need to have a quite recent Qt (5.6, maybe even 5.7 which
isn't released yet) at least at the beginning, because QtWebEngine is missing
some important features in older versions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is QtWebEngine ready?&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;It certainly wasn't when it was first released with Qt 5.4 in December 2014.&lt;/p&gt;
&lt;p&gt;That's also why I spent a lot of time writing tests for existing features
instead of trying to start working on QtWebEngine support.&lt;/p&gt;
&lt;p&gt;Nowadays with Qt 5.5/5.6/5.7 things certainly look better, and I believe I'll
be able to implement all important features, however I'll need to rewrite some
code in Javascript as there's no C++ (and thus no Python API) for all the
functionality QtWebKit had.&lt;/p&gt;
&lt;p&gt;Long story short: It's by no means a drop-in replacement (like initially
claimed by Qt) - but most users won't notice any missing functionality which I
can't implement at all with a recent enough QtWebEngine, and things are getting
better and better.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How is this blog made?&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Using &lt;a class="reference external" href="http://spacemacs.org/"&gt;spacemacs&lt;/a&gt;, writing &lt;a class="reference external" href="https://en.wikipedia.org/wiki/ReStructuredText"&gt;ReStructuredText&lt;/a&gt;, storing it in a &lt;a class="reference external" href="https://git-scm.com/"&gt;git&lt;/a&gt; repo,
processing it with &lt;a class="reference external" href="http://blog.getpelican.com/"&gt;Pelican&lt;/a&gt;, the &lt;a class="reference external" href="https://github.com/getpelican/pelican-themes/tree/master/monospace/"&gt;Monospace theme&lt;/a&gt; and the &lt;a class="reference external" href="https://github.com/getpelican/pelican-plugins/tree/master/thumbnailer"&gt;thumbnailer&lt;/a&gt;
plugin.&lt;/p&gt;
&lt;p&gt;Definitely a better workflow than Wordpress ;)&lt;/p&gt;
&lt;/div&gt;
</content><category term="pyplanet"></category><category term="qtplanet"></category><category term="pytest"></category></entry></feed>