hofer.link RSS feed https://hofer.link/rss RSS feed of hofer.link posts Dot files managed in (bare) git repo https://hofer.link/dot-git

I manage my dotfiles (mainly configs (including my custom eurokey config), but also some scripts and desktop files) by using a bare git repo to keep them version-controlled and easily portable. I didn’t invent this method—for a deep dive check out Atlassian’s tutorial.

What is a bare git repository and why do we want to use that? A bare Git repository contains only version control information without a working directory. We use it in this case because it avoids conflicts with existing directories, allows your home directory to serve as the working tree, and enables tracking files in their original locations without symlinks or nested repositories.

Setup instructions

  1. Initialize a bare git repo: git init --bare <some_location>, e.g. git init --bare /home/$USER/.local/dotfiles
  2. Create a git alias depending on your shell:

    • Fish: abbr -a cfg ’git --git-dir=<some_location> --work-tree=$HOME’ (add this to your fish config to persist it)
    • Bash: alias cfg=’/usr/bin/git --git-dir=<some_location> --work-tree=$HOME’ (similarly, add this to your .bashrc to persist it)
  3. Hide untracked files (so Git doesn’t show everything in your home directory): cfg config --local status.showUntrackedFiles no
  4. Backup to a remote repository:

    • Create an empty Git repo on your preferred Git hosting provider.
    • Add it as a remote: git remote add origin <your_repo>
    • Push your current dotfiles: git push -u origin main

That’s it! You can now use cfg instead of git to manage your dot files.

Bonus: To get notified of uncommitted changes every time you open a new shell, add this to your Fish config:

if status is-interactive
    # Commands to run in interactive sessions can go here
    git --git-dir=<some_location> --work-tree=$HOME status --porcelain
end

To set up the dotfiles on a new machine, you can simply create the alias and do git clone --bare <your_repo> <some_location>, and your personalized environment is ready to go.

Fri, 11 Apr 2025 00:00:00 +0000
Unicode https://hofer.link/unicode

I try to use hyphens and dashes correctly—mainly because it makes me happy when I see them applied properly. Additionally, I find it frustrating when I see a line break where there shouldn’t be one (e.g., between § and 1). Until now, I’ve been entering them based on the type of document I’m working on (e.g., &mdash;/&nbsp; for HTML, - - -/~ for LaTeX, ...). However, I recently switched to Obsidian and wasn’t sure how to input these characters correctly in Markdown.

To address this, I started exploring how to input these special characters more generally. One option was to map specific characters to specific keys on my keyboard, but I wanted a more general solution. As it turns out, Linux provides a handy method: you can use Ctrl+Shift+U to enter Unicode characters. For now, I’ve decided to adopt this general approach, though I may still map frequently used characters to specific keys in the future.

For my reference, here are some Unicode mappings I’ve looked into:

  • en-dash (–): 2013
  • em-dash (—): 2014
  • nbsp ( ): a0
  • double curly quote start (“): 201C
  • double curly quote end (“): 201D
  • Copyright (©): 00A9
Wed, 26 Mar 2025 00:00:00 +0000
Automatically sync files to a device upon USB connection https://hofer.link/usb-sync

I prefer not to connect my (Tolino) E-Reader to the internet. Instead, I sync my files via USB. To simplify this process, I created a script that automatically transfers all files from a specific folder to the USB device as soon as it’s plugged in. This is done with a udev rule, which is triggered whenever the USB device is connected. As it’s not recommended to mount drives within udev rules, the udev rule will invoke a systemd service which will do the mounting (via a bash script) instead.

  1. Find the idVendor and idProduct of your USB device by connecting the device via USB, and then using a tool such as lsusb from the usbutils package. lsusb should give you an output similar to this: Bus 001 Device 006: ID 0a12:3456 Rakuten Kobo Inc. tolino. The 0a12 corresponds to the idVendor, the 3456 to the idProduct.
  2. Create /etc/udev/rules.d/tolino.rules with the following contents (change the idVendor and idProduct):

    ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0a12", ATTRS{idProduct}=="3456", RUN+="/bin/systemctl start tolino"
  3. Reload your udev rules with udevadm control --reload-rules && udevadm trigger
  4. Save the following bash script, e.g. to /home/<user>/.local/bin

    #!/bin/bash
    
    # Needed for udev rule
    export XAUTHORITY=$HOME/.Xauthority
    export DISPLAY=:0
    
    sudo -u <user> DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus" /usr/bin/notify-send "Syncing tolino..."
    sudo modprobe usb-storage
    echo "Waiting until /dev/sda is visible"
    while [ ! -e /dev/sda ]; do
       sleep 1
       echo -n "."
    done
    
    while ! dd if=/dev/sda bs=2048 count=1 of=/dev/null 2>/dev/null; do sleep 1; done # wait until filesysstem detected
    [[ -d /mnt/tolino ]] || mkdir /mnt/tolino # create dir if it’s not existing
    mount /dev/sda /mnt/tolino
    
    cp --no-preserve=mode /path/which/should/be/synced/to/usb/device/* /mnt/tolino/Books/ && rm /path/which/should/be/synced/to/usb/device/*
    
    echo "Unmounting tolino..."
    umount /mnt/tolino
    
    sudo -u <user> DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus" /usr/bin/notify-send "Finished syncing tolino!"
  5. Set the executable flag: chmod +x /path/to/script/from/step/4
  6. Create /etc/systemd/system/tolino.service with the following contents:

    [Unit]
    Description=mount usb device 
    [Service]
    Type=forking
    ExecStart=/path/to/script/from/step/4
    [Install]
    WantedBy=multi-user.target
  7. Reload the systemd daemon: systemctl daemon-reload
  8. Test and enjoy it 😀 Every time you connect your e.g. E-Reader via USB, the udev rule will trigger the systemd service, which will run the script to mount the device, sync the files, and unmount the device once done. You should also receive desktop notifications when the sync process starts and finishes. Enjoy your reading!
Tue, 7 Jan 2025 00:00:00 +0000
Publicly visible <q>errors</q> https://hofer.link/publicerrors

There’s just something about catching errors that I can’t resist sharing them here whenever I find something:

  • 2025-01-17: Screen at a university, which should show which lectures are taking place in which room lecture
  • 2024-12-29: A 550 bus from Schwarzach im Pongau to Sportgastein via Böckstein seems to have an (encoding?) problem with <q>ö</q>s. This was not the case with the bus on the way back, so either they fixed the error quite quickly, or it’s just on certain buses. bus
  • 2024-12-21: The Stadtamt of Pregarten seems to be using a browser set to English for their information board information board
  • 2024-10-20: Parking lot license plate system in front of a stadium parking
  • 2024-07-27: ÖBB train (it did depart on time, although unfortunately I did not end up at the Soundtest) soundtest
Sun, 29 Dec 2024 00:00:00 +0000
Black humor at morticians https://hofer.link/funeral-humor

I recently discovered that a local funeral home in my country has some rather interesting slogans. They gave me a good chuckle, so I thought I’d keep a list here. If you know of any others, feel free to send them to me, and I’ll update this list accordingly!

  • Cigarette packaging: Smoking secures jobs!
  • Denying Corona secures jobs
  • Sleeping mask: I’m not dead, I’m just sleeping.
  • We put fun in funeral

For slogans that don’t translate well into English, I’ve kept the original German version:

  • Eiskratzer: Mit uns kratzen Sie besser ab
  • Turnleiberl/Sackerl: Ich turne bis zur Urne
  • Wir tragen unsere Kunden auf Händen
  • Wasserball: Wir lassen Dich nicht untergehen
Thu, 19 Dec 2024 00:00:00 +0000
Custom Sway keyboard mapping https://hofer.link/keymap

I thought that I had a problem: I’m an avid user of the EurKEYS keyboard layout and I wanted to type a character I (thought) I didn’t had available: §. Even though it turned out it actually is available (AltGr+Shift+s), it was a fun rabbit hole and I feel like it’s worth sharing, in case anyone wants to tweak the keyboard layout.

When you press a key on your keyboard, it sends a scancode to your computer. This scancode is a unique number that corresponds to that specific key. To find the scan code for a key, you can use e.g. extra/wev, and see that (on my machine) a has the scan code 38, s 39, and so on:

[14:     wl_keyboard] key: serial: 183354; time: 65458672; key: 38; state: 1 (pressed)
                      sym: a            (97), utf8: ’a’

[14:     wl_keyboard] key: serial: 183667; time: 65512523; key: 39; state: 1 (pressed)
                      sym: s            (115), utf8: ’s’

There are many layouts, and their scancodes differ. wayland-book has more details, if you are interested in a deep-dive on that topic.

This scancode has to be mapped to a specific character. There are different ways how this mapping is done, the most common way is to use xkb, especially since this is shipped by default in many distros. In general, wayland is able to support different input methods, but the only defined one is xkb.

The X in XKB

“There is something odd though: XKB stands for the X keyboard extension, but Sway is on Wayland. Sway uses wlroots for Wayland building blocks. This further uses libxkbcommon to parse and handle keyboard layouts. This library implements the XKB specification and does not have any relation with the X server itself. The symbols in /usr/share/X11/xkb are distributed in the xkeyboard-config package.”

© Sameer Puri, licensed under CC BY-SA 4.0

Step 1: Generate custom XKB mapping

Let’s create ~/.xkb/symbols/eurokeys-custom with the following content:

default partial alphanumeric_keys
xkb_symbols "basic" {
	include "eu"
	name[Group1] = "Custom eurokey adaption";
	key <AD10> { [ p, P, section] };
};
  • default: specifies the variant of the layout.
  • partial: Rather than writing our own mapping table from scratch, we (only) want to extend an existing definition.
  • alphanumeric_keys: Indicates that this configuration specifically applies to the alphanumeric section of the keyboard (letters, numbers, and standard symbols), as opposed to function keys, keypad keys, or other special keys.
  • xkb_symbols "basic": Definition block for the layout variant "basic".
  • include "eu": This includes all definitions from this layout as a base. The new layout will inherit all key mappings from the European layout and then apply its own modifications on top. The file can be found in /usr/share/X11/xkb/symbols/eu.
  • name[Group1] = "Custom eurokey adaption";: Name of our modification
  • key <AD10> { [ p, P, section] };: This is our actual replaced mapping. XKB does not directly use the scancode, but a more abstract naming scheme. The AD10 part was found by looking into the original EurKEY layour (/usr/share/X11/xkb/symbols/eu). Then, we can write up to 4 mappings:

    1. No modifier: just pressing the key by itself (should produce a lowercase p in our case)
    2. Shift-modifier: should produce an uppercase P
    3. AltGr-modifier: should produce our desired §
    4. AltGr+Shift-modifier: not set in our example

Step 2: Use new XKB mapping

Depending on your desktop enviroment, set the new keyboard layout. In Sway, you can do this by setting the following code in .config/sway/config:

input type:keyboard {
    xkb_layout eurokeys-custom
}
Fri, 28 Mar 2025 00:00:00 +0000
Default Applications in Linux https://hofer.link/default-apps

When you use xdg-open (et al.), or click on a (e.g., PDF) file in a file manager, the system needs to know which application to use.

xdg (Cross Desktop Group) standardizes certain aspects of the desktop experience, making it easier for applications and desktop environments to work together across different Linux distributions and desktop systems. For setting default applications, we need 2 parts from the xdg standard:

  1. A .desktop file for the program we want to execute on a certain file type. .desktop files are a standard for applications to integrate into, e.g. applications menus of desktop environments. You probably find the .desktop file of your installed program in /usr/share/applications/ or in one of these locations. For instance, the org.pwmt.zathura.desktop looks like this:

    [Desktop Entry]
    Version=1.0
    Type=Application
    Name=Zathura
    Comment=A minimalistic document viewer
    Exec=zathura %U
    Icon=org.pwmt.zathura
    Terminal=false
    Categories=Viewer;
    Keywords=PDF;PS;PostScript;DjVU;document;presentation;viewer;
  2. mimeapps.list file: Maps a MIME type to an application. You probably want to edit it in ~/.config/mimeapps.list, but there are other locations as well. Under the [Default Applications] section, you can add additional entries, e.g., application/pdf=org.pwmt.zathura.desktop.
  3. Depending on the desktop environment, you may want to set a system-wide default as well, e.g. xdg-settings set default-web-browser firefox.desktop (firefox.desktop -> ls /usr/share/applications | grep firefox)

That’s it! You should now be able to use launcher such as xdg-open on PDF files, and they should be opened in zathura.

Wed, 18 Dec 2024 00:00:00 +0000