In the middle of the desert you can say anything you want
My older approach was to use this:
run_watch VPN {
pidfile = "/etc/openvpn/mv.pid"
}
And start openvpn in a way that it writes that specific pid file.
i3: i3status(1)’s documentation points at this:
path_exists VPN {
# path exists when a VPN tunnel launched by nmcli/nm-applet is active
path = "/proc/sys/net/ipv4/conf/tun0"
}
On my computer it was tap0 instead of tun0. But it works!
My ~/.dotfiles is a symlink to another place. stow follows it, and uses as target the parent directory of the directory the symlink points to, not ~/!
Explicitly setting a target directory is stow -t ~/ thing-to-stow (interestingly, stow -t ../ also uses the parent directory relative to the symlink target of the current one).
First I did the logical thing:
alias st='stow -t ~/'
Then, after reading the manual1, created a ~/.stowrc:
--target=~/
Works now :)
Wallabag supports tagging rules based on parameters, such as domain names or reading time. Nice!
Added ww as binding to the bookmarklet.
I finally moved Fiamma (my link wiki) to a the new server! Which reminded me about the bindings I wrote to automatically format the input for the links I add there.
For example, on Ron Burk: Commas Depend on Linebreaks - Fiamma, I edited the pre-filled things to look like this:
http://ronburk.blogspot.de/2009/09/commas-depend-on-linebreaks.html
Ron Burk: Commas Depend on Linebreaks
6
5
language, linguistics, internet, style, etiquette, mildly interesting
Language
Style
Then a vim snippet from hell transformed it to
{{B|
http://ronburk.blogspot.de/2009/09/commas-depend-on-linebreaks.html
|Ron Burk: Commas Depend on Linebreaks
|6
|5
}}
{{#set:
k=language, linguistics, internet, style, etiquette, mildly interesting
|+sep=, }}
[[Category: Language]]
[[Category: Style]]
Though they were in latin-1 encoding, the .vimrc got converted to utf8, and it all got lost.
Now I have a solution. ~/.config/qutebrowser/.qb-vimrc is:
source ~/.vimrc
" let @H = 'gg<80>ýc<80>ýbi<80>ýc<80>ýb{{B|^[^[^[j0i|^[^[^[ji|j<80>kb^[^[^[ji|^[^[^[o}};q' " For the 5 lines
" let @L = 'ji{{$<80>kb%<80>kb#set:\^Mk=<80>kD^[o|+sep=,}}^[' " For the tags
" let @C = 'i[[C;tj<80>kb<80>kb<80>kbategory: ^[^[^[A]];q' " For each individual category
" let @F = 'jjVG:norm! @C\^M' "Apply that to all lines till the end
" let @d = '@H@L@F'
" let @q = '^[A^[bbbbbbi|<80>ü^B<80>kb^[:%s/=/{{=}}/ge^M'
" Summed up:
let @C = 'i[[C;tj<80>kb<80>kb<80>kbategory: ^[^[^[A]];q' " For each individual category
"let @H = '^[A^[bbbbbbi|<80>ü^B<80>kb^[:%s/=/{{=}}/ge^Mgg<80>ýc<80>ýbi<80>ýc<80>ýb{{B|^[^[^[j0i|^[^[^[ji|j<80>kb^[^[^[ji|^[^[^[o}};qji{{$<80>kb%<80>kb#set:^Mk=<80>kD^[o|+sep=,}}^[jjVG:norm! @C^M:x^M'
let @H = '^[A^[bbbbbbi|<80>ü^B<80>kb^[:%s/=/{{=}}/ge^Mgg<80>ýc<80>ýbi<80>ýc<80>ýb{{B|^[^[^[j0i|^[^[^[ji|j<80>kb^[^[^[ji|^[^[^[o}};qji{{$<80>kb%<80>kb#set:^Mk=<80>kD^[o|+sep=,}}^[jjVG:norm! @C^M' " Without closing at the end
" let @d = '@H@L@F'
" Start in insert mode
startinsert
And in qutebrowser config, I set the editor to:
c.editor.command = ['kitty', 'vim', '-u', str(config.configdir / '.qb-vimrc'), '+{line}', '{file}']
This way, standard-vim uses the standard fancy utf8 config file, but qutebrowser uses a separate one that overwrites the needed lines with the latin-1 macros. vim +10 filename means open it and put the cursor on line 10, idea comes from Reddit[^ideared
(Macros are really hard to read. How can I use something like python next time for this?)
Also - them being defined in the ~/.vimrc seems to have broken the newer ones, had to comment them out. Does vim not like redefined macros?
Updated my yank-for-markdown yank.py userscript to remove the anchor text ("…#!~:text=Text on the page to scroll to"), so I can paste it without it messing up the markdown formatting:
#!/usr/bin/python3
import os
title = os.environ['QUTE_TITLE']
title = title.replace("|", "\\|")
url = os.environ['QUTE_URL']
url = url.split("#:~:")[0]
command = "yank inline \"[{}]({})\"".format(title, url)
with open(os.environ['QUTE_FIFO'], 'w') as f:
f.write(command)
Rewrote the whole mechanism, now there’s one template that gets pre-filled by URI. First the qb userscript gets the data, writes them to a file; then opens this file in vim. When closed, it calls the new template passing the entire content of the file as first parameter.
Better because much simpler and less steps needed.
[23:07:35]
i mean, i have important work to do. dealing with an IRC network is not really something i want to be doing this decade outside of fucking around for fun with IRCX [23:07:51] i have code running on two planets 2
I think I have this time - removing state got it to start without reinstalling/changing anything.
screen in places that don’t support screenFigured out myself and kinda proud of this one. If server1 doesn’t have screen, you can ssh to it from inside screen of a server2 that does have screen! As long as the SSH connection is there it’ll work.
When doing jsons.dumps(thing) where thing has np.float32s inside it, you get the error:
TypeError: Object of type 'float32' is not JSON serializable
This is fixed by:
json.dumps(str(thing)) (though will return it as string, may or may not be what we want)np.float32s to standard python float before adding them to the objectmosquito is an ubuntu implementation of the mqtt protocol, which is “subscribe to a broker for messages of type X and you’ll get them” - seems to be a standard like REST.(from V.H’s presentation about “Как подключить вайфай к чайнику для чайников”)
German tutorial about preprocessing German with NLTK: Preprocessing
Added a zsh binding that in vi command mode launches edit-command-line to edit the current line in vim proper:
bindkey -M vicmd v edit-command-line
Doesn’t conflict with zsh-vim-mode-plugin. It’s nice how they all build upon the existing zsh infrastructure and I can keep adding my own bindings using the same mechanisms.
It puts the tensorboard files in ./runs of the directory I’m running the script from, not the output directory!
If there are a lot, the closest one to the cursor is marked , and can be selected by pressing <Enter>
Started with a new profile, and realized how much I relied on it. Apparently suggestiosn based on browsing history is integral to my productivity
Highlight the wanted lines, then :sort!
This might be a place to look for similar vim commands: Vim documentation: change
Split: how to split into different percentages? - Unix & Linux Stack Exchange:
split -l $[ $(wc -l filename|cut -d" " -f1) * 70 / 100 ] filename
This creates files called xaa and xab and works fine for my purposes.
Introduction - TIL that head doesn’t really follow them
Stop terminal auto executing when pasting a command - Ask Ubuntu:
Had unset zle_bracketed_paste in zsh config, likely needed for athame that I don’t use. Removed it, works now.
To enable in bash,
echo "set enable-bracketed-paste" >> .inputrc
I should make an eventual list of dotfiles I use for all remote servers, this will go there 100%.
Docker COPY copies contents, not directory \ Docker COPY copies contents, not directory \ Docker COPY copies contents, not directory \ Docker COPY copies contents, not directory \
Added these to kitty config! One for IPs, second IPs+ports:
map kitty_mod+n>i kitten hints --type regex --regex [0-9]+(?:\.[0-9]+){3} --program @
map kitty_mod+n>p kitten hints --type regex --regex [0-9]+(?:\.[0-9]+){3}:[0-9]+ --program @
Glad I can still read and understand regexes. The above highlight more than needed, but seems to be kitty’s problem.
In python, a group without ?: is a non-capturing group in python (= not returned in .groups()). In kitty (that uses python syntax), only what’s inside the first capturing group is copied; making it non-capturing makes it copy the entire regex. 1
I added another kitty hint to copy CLI commands currently being typed:
# CLI Commands
map kitty_mod+n>c kitten hints --type regex --regex "\$(.+)\s*$" --program @
My regex is trivial, the capturing group gets the command without the leading $ and avoids all trailing whitespaces.
The magic -dp 8000:8000 command I’ve been using is actually -d -p, with -p being what I want and -d turning on detached mode. Without it, I see the logs directly and can easily <Ctrl-c> it away.
Also, docker ps shows ports as part of the output.
Let this be the final one, with all configs correct now:
timedatectl set-timezone Europe/XXX
In the Buddhist interpretation of it, “BE WHERE YOU ARE”.
The location of the Fn key on the laptop keyboard is absolutely idiotic and I hate it. Fn keys are usually handled by the hardware and ergo unusable. Now that I have to use the keyboard more, thought I have nothing to lose and tried xev and oh what a wonderful world it gets read as XF86WakeUp! Therefore it can be remapped to something more sensible. … like the Ctrl key it should be.
Easiest way for me was adding this to autostart:
xcape -e 'XF86WakeUp=Control_L' -d &
No side effects of the other xcape command xcape -e 'Control_L=Escape' -t 100, it seems to be considered a different Control_L key and clicking it fast doesn’t produce Escape.
(Fully rewritten in 2026-05-20)
xinput disable "AT Translated Set 2 keyboard"
xinput set-prop 12 190 0 as bad alternative where:
190 is the property id for “Device Enabled”12 is the device id for the keyboardxinput set-prop 12 "Device Enabled" 0xinput disable 10
xinput disable DEVICE_IDxinput set-prop DEVICE_ID PROPERTY_ID VALUE
xinput list to get the device idxinput list-props DEVICE_ID to get the property idxinput list | grep -i "Touchpad" | grep -o "id=[0-9]*" | grep -o "[0-9]*"
xinput list | grep -i "AT Translated Set 2" | grep -o "id=[0-9]*" | grep -o "[0-9]*"
#!/bin/bash
TOUCHPAD_DEVICE_ID=$(xinput list | grep -i "Touchpad" | grep -o "id=[0-9]*" | grep -o "[0-9]*")
KEYBOARD_DEVICE_ID=$(xinput list | grep -i "AT Translated Set 2 keyboard" | grep -o "id=[0-9]*" | grep -o "[0-9]*")
# options to be displayed
k_on="KBD: enable"
k_off="KBD: disable"
t_on="Touchpad: enable"
t_off="Touchpad: disable"
# options passed to variable
options="$k_on\n$k_off\n$t_on\n$t_off"
selected="$(echo -e "$options" | rofi -lines 5 -dmenu -p "action")"
case $selected in
$k_on)
xinput --enable $KEYBOARD_DEVICE_ID;;
$k_off)
xinput --disable $KEYBOARD_DEVICE_ID;;
$t_on)
xinput --enable $TOUCHPAD_DEVICE_ID;;
$t_off)
xinput --disable $TOUCHPAD_DEVICE_ID;;
esac
It’s possible to do this instead of prefixing each command with RUN:
RUN apt-get update && \
# install base packages
apt-get install -y -qq apt-utils aptitude wget curl zip unzip sudo kmod git && \
/usr/bin/python3 -m pip install --upgrade pip && \
Changed the hint I most often use to a better binding:
# Copy url
# map kitty_mod+n>c kitten hints --type path --program @
map kitty_mod+g kitten hints --type path --program @
w track 1728 tag1 automatically ends it `now``.w continue just continues the last thing running by starting something identical starting “now” and continuing till stopped.alias icat="kitty +kitten icat"In zshrc:
autoload -Uz compinit
compinit
# Completion for kitty
kitty + complete setup zsh | source /dev/stdin
scrollback_pager vim - -c 'w! /tmp/kitty_scrollback' -c 'term ++curwin cat /tmp/kitty_scrollback'
Vim 8.0 works. Nice colorful etc.
Adding this allows to register the <Esc> key in 0.1 sec, not default 0.4.
export KEYTIMEOUT=1
A Good Vimrc - TODO
I also love his design!
GitHub - softmoth/zsh-vim-mode: Friendly bindings for ZSH’s vi mode
Out of all the various vim plugins, this is the only one I found that allows to meaningfully work with objects, like ci' etc. Also the mode indicator works very reliably.
Doesn’t conflict with zsh-evil-registers.
Ubuntu 18.04, qutebrowser etc, as usual. What helped was creating the environment with these options:
python3 scripts/mkvenv.py --pyqt-version 5.14
Should’ve done this a long time ago:
lq() {
jq . "$1" -C | less
}
From config; I should use them more.
# Select a filename and copy it
map kitty_mod+p>c kitten hints --type path --program @
#: Select a path/filename and open it with the default open program.
map kitty_mod+p>o kitten hints --type line --program -
Nicely described: How to switch between multiple GCC and G++ compiler versions on Ubuntu 20.04 LTS Focal Fossa - LinuxConfig.org
# install stuff
$ sudo apt -y install gcc-7 g++-7 gcc-8 g++-8 gcc-9 g++-9
# Add it to update-alternatives
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 7
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 7
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 8
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 8
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 9
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 9
# choose the default one
$ sudo update-alternatives --config gcc
There are 3 choices for the alternative gcc (providing /usr/bin/gcc).
Selection Path Priority Status
------------------------------------------------------------
0 /usr/bin/gcc-9 9 auto mode
1 /usr/bin/gcc-7 7 manual mode
* 2 /usr/bin/gcc-8 8 manual mode
3 /usr/bin/gcc-9 9 manual mode
Press to keep the current choice[*], or type selection number:
From the docs:
--install link name path priority
Editable installations (pip install -e .) are a thing. TODO - learn more about them.
Given that the standard ones are not enough for me, and even my additional ones for 10-20 are not enough, added a third level:
config.bind('1', 'tab-focus 1')
config.bind('2', 'tab-focus 2')
config.bind('3', 'tab-focus 3')
config.bind('4', 'tab-focus 4')
config.bind('5', 'tab-focus 5')
config.bind('6', 'tab-focus 6')
config.bind('7', 'tab-focus 7')
config.bind('8', 'tab-focus 8')
config.bind('9', 'tab-focus 9')
config.bind('0', 'tab-focus 10')
config.bind('<Alt-1>', 'tab-focus 11')
config.bind('<Alt-2>', 'tab-focus 12')
config.bind('<Alt-3>', 'tab-focus 13')
config.bind('<Alt-4>', 'tab-focus 14')
config.bind('<Alt-5>', 'tab-focus 15')
config.bind('<Alt-6>', 'tab-focus 16')
config.bind('<Alt-7>', 'tab-focus 17')
config.bind('<Alt-8>', 'tab-focus 18')
config.bind('<Alt-9>', 'tab-focus 19')
config.bind('<Alt-0>', 'tab-focus 20')
config.bind('<Alt-Ctrl-1>', 'tab-focus 21')
config.bind('<Alt-Ctrl-2>', 'tab-focus 22')
config.bind('<Alt-Ctrl-3>', 'tab-focus 23')
config.bind('<Alt-Ctrl-4>', 'tab-focus 24')
config.bind('<Alt-Ctrl-5>', 'tab-focus 25')
config.bind('<Alt-Ctrl-6>', 'tab-focus 26')
config.bind('<Alt-Ctrl-7>', 'tab-focus 27')
config.bind('<Alt-Ctrl-8>', 'tab-focus 28')
config.bind('<Alt-Ctrl-9>', 'tab-focus 29')
config.bind('<Alt-Ctrl-0>', 'tab-focus -1')
EDIT: Actually, to think of it, in for a penny, in for a pound!
for i in range(30, 60):
config.bind(','+str(i), 'tab-focus '+str(i))
Takes about 9 seconds to :config-source everything, but then works like a charm! And doesn’t seem to make anything else slower (strangely, even startup is as usual).
Opened a README.md, and see it being rendered nicely to the left. I can also edit it directly. Wow.
sed Cheat Sheet - very down-to-earth, “praxisnah”, I like it. Except for the idiotic scrolling override animations
I should use ' for the filter, " for any string elements inside it
select
jq '.results[] | select(.name == "John") | {age}' # Get age for 'John'Value VS key-value
jq '.something' gets the content of fields something removing the keyjq '. | {something}' gets key-value of something$ jq '. | select(.tokens[0]=="Tel") | .tokens[]' mvs.json
"Tel"
":"
$ jq '. | select(.tokens[0]=="Tel") | .tokens' mvs.json
[
"Tel",
":"
]
$ jq '. | select(.tokens[0]=="Tel") | {tokens}' mvs.json
{
"tokens": [
"Tel",
":"
]
}
|keys to extract keys onlyjq Cheet Sheet · GitHub also nice
TIl that you don’t need jq '. | keys', jq 'keys' etc is enough.
jq '.[-2:]''sort_by(.foo)'I think now I’m ready for the holy of holies: jq 1.4 Manual
{user, title: .titles[]} will return an array of {user, title} for each value inside .titles[]!()s around an expression means it’ll be evaluated. {(.user): .titles} will use the value of the key user!$ jq '. | {(.id): .id}' mvs.json
{
"7574": "7574"
}
\(foo)$ echo "[1,2,3]" | jq '"A string \(.)"'
"A string [1,2,3]"
It’s basically synonymous to python3’s f"My f-{string}"
'.a=23' will produce an output with .a being set to 23. Will be created if not there.
.a in the same filter after a comma will still return the old value.|= will “update” the value by running its previous value through the expression:$ echo '{"one": 23,"two":2}' | jq '.one|=(. | tostring)'
{
"one": "23",
"two": 2
}
jq -s to use, and previosu input can be piped through to it!
'[...]' can be used for the same thing. - though I can’t get this to workIt didn’t read the jq-generated multi-line output without commas between items, but jq compact mode does one record (without comma and not as part of an array) per line, and this gets parsed correctly!
JQ compact mode is jq -c '.' sth.json
Before:
{
"id": "7575",
"ner_tags": [
"6",
"6"
],
"tokens": [
"Tel",
":"
]
}
After:
{"id":"7575","ner_tags":["6","6"],"tokens":["Tel",":"]}
How to Create a Shared Directory for All Users in Linux
# Create the group
$sudo groupadd project
# Add user to this group
$sudo usermod -a -G project theuser
# Change the group of the directory
$ sudo chgrp -R project /var/www/reports/
# Turn on the `setGID` bit, so newly created subfiles inherit the same group as the directory
# And rwxrwx-rx
$ sudo chmod -R 2775 /var/www/reports/