zunzuncito

Today, prompted by a question on the #kde channel on libera, I looked into how Plasma handles its registry of recently used folders and documents. Turns out it’s way more complicated than I first thought.

The question specifically was whether there was a way to programmatically add files to Okular’s recently opened documents, so that’s where I started looking. I was already aware that some apps like Okular and Gwenview keep their own history independently from the system, and I quickly found out that Okular simply keeps a list of recently opened files in its configuration file ~/.config/okularrc of all places.

A screenshot of Okular,
KDE's PDF document viewer. The application shows its welcome page, with a button
to open a new document beside a list of recently opened documents. The latter
contains an entry for a PDF of the POSIX Base Specifications.
Okular’s welcome page, with recent documents listed.

This got me thinking. Maybe it would be a decent idea to instead have Okular interact with the system history directly. For that I first had to understand how exactly it worked.

The Standard

The way that I thought Plasma’s system history worked was through freedesktop.org’s Desktop Bookmark Specification . The gist of it is that applications read from and write to a well-known file $XDG_DATA_DIR/recently-used.xbel. Indeed that file existed and it even contained the relevant entry:

<bookmark href="IEEE%20Standard%20-%20POSIX%20Base%20Specifications,%20Issue%208,%202024.pdf">
<info>
  <metadata owner="http://freedesktop.org">
    <mime:mime-type type="application/pdf"/>
    <bookmark:applications>
      <bookmark:application name="org.kde.okular" exec="okular %u" count="1"/>
    </bookmark:applications>
  </metadata>
</info>
</bookmark>

Okular then seemed to write to both recently-used.xbel and okularrc when instead it could simply access the former directly and keep all history entries out of its configuration file. What’s more, having Okular forget its history would only clear the entry in okularrc.

The most prominent place in which system history is displayed is in Dolphin’s “Recent Files” panel. After clearing Okular’s history entry I still found the document there, so it seemed obvious to assume that it uses recently-used.xbel. Dolphin lets you forget specific entries from history, so I confidently deleted the entry there and re-checked the file. Weirdly, the entry was still there even though Dolphin didn’t show it anymore…

It was time to delve into the code. Untangling all the interconnected parts took a while, but after a good 10 minutes, I finally knew what was going on: There was another history provider.

The Other “Standard”

This is where I have to mention KDE’s activities. Activities are a somewhat ill-defined concept but they basically boil down to the idea of providing a different computing space depending on what you are doing at the moment. In reality the most obvious user-facing activity feature in Plasma 6 is that you can customize your task bar and wallpaper per activity so you could consider it an extension of virtual desktops - applications open on one activity won’t be shown once you switch to another.

Crucially, however, the activity subsystem kactivitymanagerd is also used to manage recently opened files. I imagine the plan is (or was) to enable tracking file history per activity, but in all my testing I could not get this to work - history seems to be global. So what this essentially means is that an application might, and most probably will:

  1. Keep its own history, most of the time through KRecentFilesAction and a simplistic history implementation. The data here is exclusively accessed by the application itself.

  2. Keep its history in the desktop-agnostic recently-used.xbel file. In KDE’s case this usually does not happen in the application itself but instead through its KIO framework. Other desktop systems might read and display this data, but KDE seems to be write-only: history is appended, but never shown to the user.

  3. Keep its history in an SQLite database under ~/.local/share/kactivitymanagerd, managed by a daemon. This is what you see in Dolphin and what you can manage under “Recent Files” in the system settings.

It also means that if you want to tweak history management, forget documents or folders, or turn the thing(s) off, you have to look in a multitude of places:

  1. If the application provides a setting to manage or disable its own history, use that. If that’s not available (like in Okular) you’re out of luck. Disabling an application’s own history will not impact the other two history providers - you will still see recent files in Dolphin and elsewhere in the system.

  2. There’s been ongoing work to streamline management of entries in recently-used.xbel, spurred by this bug. You may also use the undocumented UseRecent, MaxEntries, and IgnoreHidden options read from ~/.config/kdeglobals.

  3. Tweak kactivitymanagerd history in system settings under “Recent Files”.

Forgetting History

With all this in mind my immediate reaction is to shy away from the whole endeavour to have Okular interface with the system history - there’s too many moving parts, some of which aren’t even yet well-defined on KDE’s side.

The freedesktop.org shared MIME-info database spec says the following in section 2.11:

A type is a subclass of another type if any instance of the first type is also an instance of the second. For example, all image/svg+xml files are also application/xml, text/plain and application/octet-stream files. Subclassing is about the format, rather than the category of the data (for example, there is no ‘generic spreadsheet’ class that all spreadsheets inherit from).

Some subclass rules are implicit:

  • All text/* types are subclasses of text/plain.
  • All streamable types (ie, everything except the inode/* types) are subclasses of application/octet-stream.

So far so good; this makes intuitive sense and seems sensible enough. There is an interesting consequence of this rule when the MIME-info database is used by desktop systems for file associations, however: An application associated with application/octet-stream will automatically be associated with all streamable types as well.

This means that if you associate application/octet-stream with your text editor, your desktop system will also suggest you open video and audio files with that same text editor. This behaviour can be quite surprising, especially if the association was added automatically when a file was opened through the “Open with…” dialog.

What is even more confusing if you don’t happen to know the subclassing rule is the fact that ~/.config/mimeapps.list and applications interfacing with this file will not even list the editor as associated with any audio or video files. You might just skip over the entry it has for application/octet-stream, not realizing its significance. Perhaps you even assume (understandably) that application/octet-stream only specifies any file of “unknown” type. User-facing documentation on desktop systems (if it even exists) does not discuss this behaviour.

Whilst looking into this I found an older KDE bug report with some interesting thoughts on how to explain this behaviour to the end user, but sadly as far as I have seen none of these have made it into the system setting’s file association dialog.

The file manager I’m using on my Plasma 6 system, Dolphin, has built-in support for remote folders via the KIO framework. Where before I was relying on sshfs mount points in /etc/fstab, I decided to try out the Dolphin way and set up my remote devices using its sftp backend.

After a couple of days now I can say that this works beautifully… until you want to access the remote device on something that does not interface with KIO. This is especially important for me (and others) since I want to be able to browse networked filesystems via my terminal and have the ability to directly open a terminal in that location through Dolphin, something which is not possible with the KIO backend.

So in the end I went back to mount points in /etc/fstab. One small problem remained, however, and that was the way those mount points were displayed within Dolphin. There seemed to be no way to customize a mount point’s name or icon, leading to an annoyingly long /home/wolf/net/hosts/coleridge entry in the Devices section of Dolphin’s places panel.

I couldn’t find any help in fstab(5), and indeed I had never heard of a way to give a mount point a “pretty name”. However, after a bit of searching, I found people offhandedly mentioning the x-gvfs-name option. Some more searching revealed that nobody seems to care about documenting these features, but I was finally able to find an authoritative source within gvfs itself.

Happily there’s not only x-gvfs-name but also support for custom icons through x-gvfs-icon. So, if you want your file manager to display a pretty name and icon for one of your mount points, simply add the following to the relevant entry in /etc/fstab:

x-gvfs-name=My%20Device,x-gvfs-icon=network-server

This should be possible at least on GNOME and KDE desktops. I imagine a bunch of other environments and programs silently support this behaviour as well.

A screenshot of Dolphin, KDE's
file manager, showing the user's home directory with the places panel on the
left side containing various categorized entries. The entries below the Devices
category read flood, demeter, coleridge, and OnePlus 12, each with its own
pretty name and relevant icon.
Dolphin displaying pretty names and icons in the Devices category

Thunar, XFCE’s file manager, was a pretty late addition to my core set of tools that I rely on to accomplish day-to-day tasks. I started using it heavily maybe 2 or 3 years ago. For the longest time before that I had been using ranger, a console file manager.

The ability to move and copy files around between multiple directories using drag-and-drop is basically Thunar’s killer feature for me. I’m often faster using the mouse to select a bunch of files and then quickly dragging them someplace else. In comparison, ranger’s select-then-yank-and-paste workflow feels very cumbersome.

However, there’s always been a feature in ranger that Thunar did not have - the very simple but powerful ability to filter the current directory listing by showing only files matching a given pattern. There’s a more or less hidden way to have Thunar select files matching a wildcard with CTRL-S, but that relies on popping up an extra dialogue, and doesn’t play well with interactive use.

Very early on I found a feature request for this, but it looked largely abandoned and I forgot about it until today when, to my extreme surprise, I discovered that it was implemented just 3 months ago. There does not seem to have been any large fanfare around it; the changelog buries it in more miscellaneous changes. Not a big deal.

Way more worrisome, however, is that the commit implementing the feature does not introduce any user-facing documentation. Nowhere is explained how the new feature works and what its limitations are. I had to go read the code to find out why my search results were littered with seemingly random files in other directories. Turns out that it consults files in GtkRecent too, merging results in the current directory with matches of files you had recently opened, regardless of their location.

A terrible default in my opinion, so I immediately turned it off by disabling the gtk-recent-files-enabled property in my GTK config. Thankfully you can still do that, albeit in a system-wide fashion, but I don’t care about recent files.

Still, it’s really sad I had to go out of my way to find that out. A less tech-savvy user could not have done that so easily. It would lower the bar tremendously here to describe what a new feature does and point out how to configure it.

A failure to do so makes software intransparent and hostile, furthers the notion that the user experience is inherently bad, and very quickly leads to resignation in the common user base.

A couple of days ago I turned on hidepid=2 for the /proc mount on my desktop PC. Today I saw the systemd-userdbd service failing on bootup, and realized that it had been failing to start for a few days. Aside from the fact that there really should be a well-supported and easy way to notify administrators of failing units, this obviously needed some investigation.

systemctl status systemd-userdbd.service wasn’t very helpful, but journalctl had the specific error:

[..] spawning /lib/systemd/systemd-userdbd: Read-only file system

I didn’t immediately jump to the conclusion that this had to do with enabling hidepid=2. After all, why would that result in a read-only file system? Investigating a failure very early on in boot is a pain, so instead of wasting my time on that I took to GitHub issues.

As it turns out, hidepid= is just not supported at all in systemd. This doesn’t seem to be pointed out anywhere, and I certainly was not aware of it before. Services can set ProtectProc=, but there doesn’t seem to be a clean way of restricting /proc for unprivileged users like a global hidepid=2 did. I’ve removed the option for now.

Yesterday whilst catching up on the Git mailing list I stumbled upon this patch proposing to improve the hunk header regex for Java. I had never paid much attention to how git-diff(1) finds the right method signature to show in the headers though I was vaguely aware of a bunch of regexes for different languages.

Turns out that by default, as explained in the manual for gitattributes(5), git-diff(1) emulates the behaviour of GNU diff -p and does not consult any of the language-specific regular expressions. This came as a bit of a surprise to me, as Git usually has relatively sane and extensive defaults. Why define all these regexes and then not use them by default?

Perhaps one reason is that it is hard to tell when to use which. Git can only look at the filename, and not all shell scripts share the .sh ending, for example. Surely it would not be too invasive, however, to define sensible defaults for, say, files ending in .py or .rs.

In any case I updated my ~/.config/git/attributes with the following, and am now enjoying better hunk headers across the board:

*.c	diff=cpp
*.cpp	diff=cpp
*.go	diff=go
*.md	diff=markdown
*.pl	diff=perl
*.py	diff=python
*.rs	diff=rust
*.sh	diff=bash
*.tex	diff=tex

The markdown setting is especially neat since it will now display the nearest section right in the diff, like so:

--- a/posts/weltschmerz.md
+++ b/posts/weltschmerz.md
@@ -24,6 +24,10 @@ ## Download

In the previous post I talked about a couple of different ways to apply patches with mutt(1) or neomutt(1). Turns out Maildir might not be the best format to use for git-am(1) because its files are not guaranteed to be in any specific order (per spec they need only carry unique names).

As git-am(1) does not sort its input, patches might be applied in the wrong order. This came up on the mailing list as well, all the way back in 2013. A fix specific to Maildir files created by mutt(1) was added in 18505c3.

Sadly neomutt(1) changed this format 5 years ago, removing the sequence number that git-am(1) relies on in commit 75b3708 and replacing it with a call to mutt_rand64(). I can only assume no one is using neomutt(1) to export patches to Maildir, since having patches applied in the wrong order is a pretty significant problem.

For now I recommend using the mbox format instead when exporting patches. Whilst that doesn’t guarantee a specific order either, usually mail clients are nice enough to export mails to mbox in the order they are shown.

The core issue remains until git-am(1) learns to sort mails itself.

When maintaining a project sooner or later there comes the time when you need to apply patches that have been submitted to you. Assuming a patch-based workflow, those are going to be one patch per mail, possibly connected in a thread. There’s lots of different ways of getting those patches to their final destination, git-am(1), and in this post I want to take a look at ones that work well with mutt(1) or neomutt(1) since that is what I use.

I want to rely on the default bindings as much as possible. All mentioned bindings should work out of the box.

Applying a single patch is very straightforward: Select the mail in the pager and hit | to pipe it to an external command. This command will be some variation of git-am(1), perhaps git am -s to also add a Signed-off-by trailer.

What if you want to apply a patch series, however? An obvious solution would be to pipe each message in the thread to git-am(1). The <pipe-message> command we invoked earlier with | only applies to the currently selected message, so we can’t use that on the whole thread. Instead we can tag the whole thread using <Esc>t, then use the <tag-prefix> command ; followed by | to send all tagged messages to git-am(1).

There’s two problems with this, though. The first is that depending on the setting of pipe_split, git-am(1) might only apply the first patch in the series. This is the case if pipe_split is set to the default of no; mutt(1) will then concatenate the messages before sending them to the external command. Sadly this concatenated format is slightly different from the mbox format that git-am(1) expects, making it not see anything past the first patch.

With pipe_split set to yes, mutt(1) spawns one process per tagged mail instead, applying all patches correctly. Now that git-am(1) is spawned once per mail, however, you lose its atomicity: Neither ORIG_HEAD will be set correctly, nor will --abort go back to the original branch.

This might not be a big issue, but I am not a fan. Thankfully git-am(1) supports reading patches from mbox files or Maildir structures. So instead of piping mails to git-am(1) via <pipe-message>, let’s save them to the current directory: With the thread still tagged, ;C (<tag-prefix> followed by <copy-message>) will save a copy of it under a given path. Now you can apply the series by hitting ! and running git am -s <path>. This works with mbox_type set to either mbox or Maildir (but see № 9 ).

Of course there is no need to rely on the default bindings, especially if you need to do this kind of thing very often. mutt(1) is easily customizable, making it possible to bind the entire chain of actions to just one keystroke. If you’re interested in a more detailed examination of a patch-based workflow with mutt(1), check out this post by Greg Kroah-Hartman.

I recently became frightfully aware of how much time I spend in less(1).

It’s never been a utility I gave much conscious thought and I realized that it is one of those programs that go largely ignored and underappreciated just for their ubiquity and unobtrusiveness. For most people piping something to less(1) has most likely become second nature. In the same way it is surely unthinkable for some to read log files and manuals in anything other than less(1), or use any other pager for the Git suite.

If you’ve not given less(1) a closer look, I invite you to read its manual. There’s lots of neat features you might have missed, like filtering lines with &, toggling any command-line option on the fly with -, following input as it appears with F, or opening the current file in an editor with v.

A feature I discovered only recently is the “wrap-around search modifier”. Introduced in late 2020 (past version 565), this modifier obsoletes the common dance of g and n to redo the current search on the whole file. Now, if you hit Ctrl-W right after issuing a forward or backward search, less(1) toggles search wrap-around.

There is no option to turn this behaviour on automatically. However, it is possible to override the / and ? bindings using lesskey(1). Put the following in ~/.lesskey, run lesskey (not needed on versions past 590), and less(1) should now wrap the search automatically:

#command
/ forw-search ^W
? back-search ^W

HTTP defines the Link header with which Link Relations can be defined directly in the HTTP response. This lets websites define their stylesheets or favicons without having to pass them in an HTML <link> element.

When displaying certain files directly, Firefox wraps them in its own HTML. This happens, for example, when you look at a .txt file marked as text/plain or an image marked as image/png.

Turns out that for plain-text files, Firefox will load and honour any stylesheet passed to it in the Link header and apply it to its own HTML. One could, for example, link a stylesheet that overrides the font settings, or even include pictures. Firefox will duly load all of these when displaying the file, whilst View Page Source will still show only the file itself. It is only when looking at the HTTP response and the Network tab in the Inspector that you see what exactly is happening.

Firefox displaying a plain-text file
alongside a picture.
A plain-text file… in Comic Sans… that also displays a picture?

This does not seem to work when Firefox is displaying images and it doesn’t work at all in Chromium-based browsers. The only relevant entry in Mozilla’s Bugzilla instance I could find was this issue from 9 years ago.

Arguably this could be considered a bug, and I do strongly feel that Firefox should not load any outside resource when displaying plain-text files. For now, though, have fun confusing people with this.

Thanks to puck for pointing this out to me.

Whilst reviewing and discussing this patch for weltschmerz I found out that there actually exists a global property gtk-cursor-blink that is honoured by all applications that build on GTK.

I don’t think I’ve ever seen this exposed in a settings dialog. Perhaps in the accessibility settings, I rarely venture there. In any case, you can put properties like these straight into ~/.config/gtk-3.0/settings.ini and GTK apps will pick them up.

For QT apps it seems you can set cursorFlashTime to a negative value in the aptly named ~/.config/Trolltech.conf but I could not get this to work with the only QT app that I use, quassel.

Not that I would want to, I do prefer a blinking cursor.

The notion of a “merged” branch is highly dependent on the workflow used for a project. I was wanting to clean up some topic branches in my copy of git.git today, but git branch -d refused to delete them, pointing out that they were not yet merged.

I knew for a fact that they were, which made me look up how git branch -d actually determines that. The manual is not entirely clear, but a comment in the code pointed out that git constructs the merge base of the branch and its upstream (or HEAD if there is none) and checks whether the branch is reachable from that merge base.

In a patch workflow, this will generally not be true. A lot of things may happen to your patches before inclusion, and with git.git they will get at least one other sign-off. They’ll be recorded in a merge commit, but it will not have your original branch as one of its parents.

Therefore, neither git branch -d nor git branch --merged will report your branch as merged. Both of these tools are built for the merge workflow instead.

To see if your work was merged in patch-based workflows, use git-cherry(1). Then you can safely force deletion of the branch with git branch -D

In recent versions of Firefox, single words are looked up via DNS when you enter them in the URL bar. If the word resolves, the browser “helpfully” indicates that there’s a page at http://<word> to visit.

Weird feature, though when taken at face value I can see its usefulness with a combined search and URL bar. Ideally you’d have completely different semantics for searching and (direct) browsing, but I don’t think something like this is forthcoming. If anything I’d expect direct browsing to be ever more discouraged. Nowadays search engines, not browsers, are the gateway to the internet.

In any case, turns out this feature also has interesting side-effects with (browser-based) DoH turned on. If you ever need to turn it off, Firefox 78 added the following about:config switch:

browser.urlbar.dnsResolveSingleWordsAfterSearch

Not that I think this is a great solution. DoH should be done on a system-wide level (with local queries sent to your router or resolved through mDNS) and there should be a way of trusting your router’s DNS to not forward local queries to your ISP.