feat(configs): publish configs done

This commit is contained in:
Pavel Korytov 2021-08-22 13:13:38 +03:00
parent 7937c70bcb
commit 77fea9ad09
51 changed files with 34037 additions and 127 deletions

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "themes/researcher"]
path = themes/researcher
url = git@github.com:ojroques/hugo-researcher.git

View file

@ -11,6 +11,7 @@ staticDir = ["static"]
# logo = "logo.svg"
[params.footer]
text = "Pavel Korytov, 2021"
mainSections = ['posts']
[permalinks]
"/" = "/:filename"

1099
content/configs/Console.md Normal file

File diff suppressed because it is too large Load diff

1099
content/configs/Console.md~ Normal file

File diff suppressed because it is too large Load diff

2743
content/configs/Desktop.md Normal file

File diff suppressed because it is too large Load diff

2743
content/configs/Desktop.md~ Normal file

File diff suppressed because it is too large Load diff

6175
content/configs/Emacs.md Normal file

File diff suppressed because it is too large Load diff

6175
content/configs/Emacs.md~ Normal file

File diff suppressed because it is too large Load diff

819
content/configs/Guix.md Normal file
View file

@ -0,0 +1,819 @@
+++
title = "Guix"
author = ["Pavel"]
draft = false
+++
[GNU Guix](https://guix.gnu.org/) is (1) a transactional package manager and (2) a GNU/Linux distribution.
My personal selling points are declarative package configuration and transactional upgrades.
References:
- [Official help](https://guix.gnu.org/en/help/)
- [System Crafters wiki](https://wiki.systemcrafters.cc/guix)
- [Pjotr Prins' Guix notes](https://gitlab.com/pjotrp/guix-notes)
- [Davil Wilson's YouTube series](https://www.youtube.com/watch?v=iBaqOK75cho&list=PLEoMzSkcN8oNxnj7jm5V2ZcGc52002pQU)
<div class="ox-hugo-toc toc">
<div></div>
<div class="heading">Table of Contents</div>
- [Contents](#contents)
- [Profiles](#profiles)
- [Activate profiles](#activate-profiles)
- [Update profiles](#update-profiles)
- [Channels](#channels)
- [Systems](#systems)
- [Base configuration](#base-configuration)
- [indigo](#indigo)
- [eminence](#eminence)
- [azure](#azure)
- [System installation](#system-installation)
- [Preparation](#preparation)
- [Installation](#installation)
- [After installation](#after-installation)
- [Misc software & notes](#misc-software-and-notes)
- [VPN](#vpn)
- [vpn-start](#vpn-start)
- [vpn-stop](#vpn-stop)
- [flatpak](#flatpak)
- [conda](#conda)
- [Slack](#slack)
- [virt-manager](#virt-manager)
- [wakatime-cli](#wakatime-cli)
- [Manifest](#manifest)
</div>
<!--endtoc-->
## Contents {#contents}
- [Contents](#contents)
- [Profiles](#profiles)
- [Activate profiles](#activate-profiles)
- [Update profiles](#update-profiles)
- [Channels](#channels)
- [Systems](#systems)
- [Base configuration](#base-configuration)
- [indigo](#indigo)
- [eminence](#eminence)
- [azure](#azure)
- [System installation](#system-installation)
- [Preparation](#preparation)
- [Installation](#installation)
- [After installation](#after-installation)
- [Misc software & notes](#misc-software-and-notes)
- [VPN](#vpn)
- [vpn-start](#vpn-start)
- [vpn-stop](#vpn-stop)
- [flatpak](#flatpak)
- [conda](#conda)
- [Slack](#slack)
- [virt-manager](#virt-manager)
- [wakatime-cli](#wakatime-cli)
- [Manifest](#manifest)
## Profiles {#profiles}
A profile is a way to group Guix packages. Amongst its advantages, profiles can be defined by manifests, which in turn can be stored in VCS.
References:
- [Guix Profiles in Practice](https://guix.gnu.org/en/cookbook/en/html%5Fnode/Guix-Profiles-in-Practice.html)
### Activate profiles {#activate-profiles}
A script to activate guix profiles. Usage:
```text
activate-profiles [profile1] [profile2] ...
```
Source: [David Wilson's config](https://github.com/daviwil/dotfiles/blob/master/Systems.org#activating-profiles)
```bash
GREEN='\033[1;32m'
RED='\033[1;30m'
NC='\033[0m'
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
profiles=$*
if [[ $# -eq 0 ]]; then
profiles="$HOME/.config/guix/manifests/*.scm";
fi
for profile in $profiles; do
# Remove the path and file extension, if any
profileName=$(basename $profile)
profileName="${profileName%.*}"
profilePath="$GUIX_EXTRA_PROFILES/$profileName"
manifestPath=$HOME/.config/guix/manifests/$profileName.scm
if [ -f $manifestPath ]; then
echo
echo -e "${GREEN}Activating profile:" $manifestPath "${NC}"
echo
mkdir -p $profilePath
guix package --manifest=$manifestPath --profile="$profilePath/$profileName"
# Source the new profile
GUIX_PROFILE="$profilePath/$profileName"
if [ -f $GUIX_PROFILE/etc/profile ]; then
. "$GUIX_PROFILE"/etc/profile
else
echo -e "${RED}Couldn't find profile:" $GUIX_PROFILE/etc/profile "${NC}"
fi
else
echo "No profile found at path" $profilePath
fi
done
```
### Update profiles {#update-profiles}
A script to update Guix profiles. Usage:
```text
update-profiles [profile1] [profile2] ...
```
Source: once again, [David Wilson's config](https://github.com/daviwil/dotfiles/blob/master/Systems.org#updating-profiles).
```bash
GREEN='\033[1;32m'
NC='\033[0m'
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
profiles=$*
if [[ $# -eq 0 ]]; then
profiles="$GUIX_EXTRA_PROFILES/*";
fi
for profile in $profiles; do
profileName=$(basename $profile)
profilePath=$GUIX_EXTRA_PROFILES/$profileName
echo
echo -e "${GREEN}Updating profile:" $profilePath "${NC}"
echo
guix package --profile="$profilePath/$profileName" --manifest="$HOME/.config/guix/manifests/$profileName.scm"
done
```
## Channels {#channels}
Specifying additional channels.
[channel-q](https://github.com/SqrtMinusOne/channel-q) is my Guix channel. Don't use it at home.
References:
- [nonguix channel repo](https://gitlab.com/nonguix/nonguix)
- [Guix channels reference](https://guix.gnu.org/manual/en/html%5Fnode/Channels.html)
<!--listend-->
```scheme
(cons*
(channel
(name 'channel-q)
(url "file:///home/pavel/Code/channel-q"))
(channel
(name 'flat)
(url "https://github.com/flatwhatson/guix-channel.git")
(introduction
(make-channel-introduction
"33f86a4b48205c0dc19d7c036c85393f0766f806"
(openpgp-fingerprint
"736A C00E 1254 378B A982 7AF6 9DBE 8265 81B6 4490"))))
(channel
(name 'nonguix)
(url "https://gitlab.com/nonguix/nonguix")
;; (commit "d54973e47b89fe5772a5b6e2d0c0b86acb089e27")
(introduction
(make-channel-introduction
"897c1a470da759236cc11798f4e0a5f7d4d59fbc"
(openpgp-fingerprint
"2A39 3FFF 68F4 EF7A 3D29 12AF 6F51 20A0 22FB B2D5"))))
%default-channels)
```
## Systems {#systems}
Configuring systems with Guix.
Yes, all my machines are named after colors I like.
### Base configuration {#base-configuration}
The base configuration is shared between all the machines.
While it's possible to make a single `.scm` file with base configuration and load it, I noticed that it produces more cryptic error messages whenever there is an error in the base file, so I opt-in for noweb.
`guix system` invocation is as follows:
```text
sudo -E guix system reconfigure ~/.config/guix/systems/[system].scm
```
Common modules:
```scheme
(use-modules (gnu))
(use-modules (gnu system nss))
(use-modules (gnu packages bash))
(use-modules ((gnu packages base) #:select (coreutils glibc)))
(use-modules (gnu packages certs))
(use-modules (gnu packages version-control))
(use-modules (gnu packages vim))
(use-modules (gnu packages gnome))
(use-modules (gnu packages xorg))
(use-modules (gnu packages wm))
(use-modules (gnu packages openbox))
(use-modules (gnu services docker))
(use-modules (gnu services cups))
(use-modules (gnu services virtualization))
(use-modules (srfi srfi-1))
(use-modules (guix channels))
(use-modules (guix inferior))
(use-modules (nongnu packages linux))
(use-modules (nongnu system linux-initrd))
(use-service-modules desktop networking ssh xorg nix)
(use-package-modules ssh)
```
In principle, we could define a variable called `base-operating-system` and extend it in ancestors. However, then we would have to define mandatory fields like `host-name`, `bootloader` with dummy values. Since I'm already using noweb, there is little point.
The following code will be inserted at the top of the `operating-system` definition.
Use the full Linux kernel. I hope I'll be able to use Libre kernel somewhere later.
Inferior in the kernel is used to avoid recompilation. It looks like I can pin these to different commits than in my `channels.scm`
```scheme
(kernel
(let*
((channels
(list (channel
(name 'nonguix)
(url "https://gitlab.com/nonguix/nonguix")
(commit "d3c5eea0cbfe3e5bfbcf1fe15bc916fefacc624f"))
(channel
(name 'guix)
(url "https://git.savannah.gnu.org/git/guix.git")
(commit "cf88c967afbf15c58efb0ba37d6638f1be9a0481"))))
(inferior
(inferior-for-channels channels)))
(first (lookup-inferior-packages inferior "linux" "5.12.9"))))
;; (kernel linux)
(initrd microcode-initrd)
(firmware (list linux-firmware))
(locale "en_US.utf8")
(timezone "Europe/Moscow")
```
US/RU keyboard layout, switch with Alt+Shift.
```scheme
(keyboard-layout (keyboard-layout "us,ru" #:options '("grp:alt_shift_toggle")))
```
User accounts.
```scheme
(users (cons* (user-account
(name "pavel")
(comment "Pavel")
(group "users")
(home-directory "/home/pavel")
(supplementary-groups
'("wheel" ;; sudo
"netdev" ;; network devices
"audio"
"video"
"input"
"tty"
"docker"
"scanner"
"libvirt"
"lp")))
%base-user-accounts))
```
Base packages, necessary right after the installation.
```scheme
(packages
(append
(list nss-certs
git
i3-gaps
i3lock
openbox
xterm
vim)
%base-packages))
```
Default services for each machine:
- override the default `%desktop-services` to add OpenVPN support
- add nix service
- add docker service
- add CUPS service
- add libvirt service
- add a symlink to ELF interpreter to where most Linux binaries expect it
<!--listend-->
```scheme
(define %my-base-services
(cons*
(service openssh-service-type)
(screen-locker-service i3lock "i3lock")
(extra-special-file "/lib64/ld-linux-x86-64.so.2" (file-append glibc "/lib/ld-linux-x86-64.so.2"))
(service nix-service-type)
(service cups-service-type
(cups-configuration
(web-interface? #t)))
(service docker-service-type)
(service libvirt-service-type
(libvirt-configuration
(unix-sock-group "libvirt")
(tls-port "16555")))
(service virtlog-service-type)
(modify-services %desktop-services
(network-manager-service-type
config =>
(network-manager-configuration
(inherit config)
(vpn-plugins (list network-manager-openvpn)))))))
```
### indigo {#indigo}
`indigo` is my desktop PC.
```scheme
<<system-common>>
(operating-system
<<system-base>>
(host-name "indigo")
(services (cons*
(set-xorg-configuration
(xorg-configuration
(keyboard-layout keyboard-layout)))
%my-base-services))
(bootloader
(bootloader-configuration
(bootloader grub-efi-bootloader)
(target "/boot/efi")
(keyboard-layout keyboard-layout)))
(swap-devices
(list (uuid "059a2c26-8f70-4986-adf0-1a2e7b511404")))
(file-systems
(cons* (file-system
(mount-point "/")
(device (file-system-label "my-root"))
(type "ext4"))
(file-system
(mount-point "/boot/efi")
(device "/dev/sda1")
(type "vfat"))
%base-file-systems)))
```
### eminence {#eminence}
`eminence` is a HP 15s laptop.
`%backlight-udev-rule` should enable members of `video` group change the display backlight. See the relevant page at [Arch Wiki](https://wiki.archlinux.org/title/Backlight).
```scheme
<<system-common>>
(define %backlight-udev-rule
(udev-rule
"90-backlight.rules"
(string-append "ACTION==\"add\", SUBSYSTEM==\"backlight\", "
"RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""
"\n"
"ACTION==\"add\", SUBSYSTEM==\"backlight\", "
"RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\"")))
(operating-system
<<system-base>>
(host-name "eminence")
(services (cons*
(set-xorg-configuration
(xorg-configuration
(keyboard-layout keyboard-layout)))
(modify-services %my-base-services
(elogind-service-type
config =>
(elogind-configuration
(inherit config)
(handle-lid-switch-external-power 'suspend)))
(udev-service-type
config =>
(udev-configuration
(inherit config)
(rules (cons %backlight-udev-rule
(udev-configuration-rules config))))))))
(bootloader
(bootloader-configuration
(bootloader grub-efi-bootloader)
(target "/boot/efi")
(keyboard-layout keyboard-layout)))
(swap-devices
(list (uuid "f93cf3f6-7ee7-42ec-8ee2-f3d896fdf9b5")))
(file-systems
(cons* (file-system
(mount-point "/")
(device
(uuid "1d937704-bbeb-43b5-bc63-453886c426af"
'ext4))
(type "ext4"))
(file-system
(mount-point "/boot/efi")
(device (uuid "0031-3784" 'fat32))
(type "vfat"))
%base-file-systems)))
```
### azure {#azure}
`azure` is a Lenovo Ideapad 330 laptop.
`%backlight-udev-rule` should enable members of `video` group change the display backlight. See the relevant page at [Arch Wiki](https://wiki.archlinux.org/title/Backlight).
```scheme
<<system-common>>
(define %backlight-udev-rule
(udev-rule
"90-backlight.rules"
(string-append "ACTION==\"add\", SUBSYSTEM==\"backlight\", "
"RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""
"\n"
"ACTION==\"add\", SUBSYSTEM==\"backlight\", "
"RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\"")))
(operating-system
<<system-base>>
(host-name "azure")
(services (cons*
(set-xorg-configuration
(xorg-configuration
(keyboard-layout keyboard-layout)))
(modify-services %my-base-services
(elogind-service-type config =>
(elogind-configuration (inherit config)
(handle-lid-switch-external-power 'suspend)))
(udev-service-type config =>
(udev-configuration (inherit config)
(rules (cons %backlight-udev-rule
(udev-configuration-rules config))))))))
(bootloader
(bootloader-configuration
(bootloader grub-efi-bootloader)
(target "/boot/efi")
(keyboard-layout keyboard-layout)))
(swap-devices
(list (uuid "4b2dedb3-b111-4e69-8c05-6daa2b072c76")))
(file-systems
(cons* (file-system
(mount-point "/")
(device (file-system-label "my-root"))
(type "ext4"))
(file-system
(mount-point "/boot/efi")
(device "/dev/sda1")
(type "vfat"))
%base-file-systems)))
```
## System installation {#system-installation}
### Preparation {#preparation}
In my case, the provided ISO doesn't work because of the Libre kernel.
Fortunately, David Wilson has made [a repository](https://github.com/SystemCrafters/guix-installer) with a toolchain to make an ISO with the full kernel. In case it won't be an option, the [nonguix repo](https://gitlab.com/nonguix/nonguix) also has instructions on how to do that.
When an ISO is there, we have to write it on a USB stick. Run `sudo fdisk -l` to get a list of disks.
The approach in the official instruction is to create a bootable USB with `dd`:
```text
sudo dd of=/dev/sdxX if=<path-to-iso> status=progress && sync
```
However, I couldn't make it work for some strange reason. Fortunately, `gnome-disk-utility` was able to produce a bootable USB.
### Installation {#installation}
Going further, the official instructions for installation & SystemCrafters wiki entry are pretty good, so it's not necessary to repeat them here.
### After installation {#after-installation}
After the installation, the strategy is as follows.
Set a password for the main user (pavel). Login with openbox to get a tolerable interface because the i3 default config is horrible.
[Connect to the internet](https://guix.gnu.org/en/manual/en/html%5Fnode/Keyboard-Layout-and-Networking-and-Partitioning.html#Keyboard-Layout-and-Networking-and-Partitioning).
Clone the dotfiles repo:
```text
mkdir Code
cd Code
git clone https://github.com/SqrtMinusOne/dotfiles.git
```
Copy the channels file and run guix pull:
```text
cp ~/Code/dotfiles/.config/guix/channels.scm ~/.config/guix
guix pull
```
The first pull usually takes a while. After that install yadm and pull dotfiles:
```text
guix install yadm
guix clone https://github.com/SqrtMinusOne/dotfiles.git
```
And activate the required profiles. Again, downloading & building Emacs, Starship and stuff will take a while.
Don't forget to install `JetBrainsMono Nerd Font`.
## Misc software & notes {#misc-software-and-notes}
| Category | Guix dependency | Description |
|----------|-----------------|----------------------------------------------------|
| system | patchelf | A program to modify existsing ELF executables |
| system | glibc | A lot of stuff, including ELF interpeter and `ldd` |
### VPN {#vpn}
| Category | Guix dependency |
|----------|-----------------------------|
| system | openvpn |
| system | openvpn-update-resolve-conf |
I'm not sure how to properly spin up VPN on Guix, so here is what I'm doing now, after some trial and error.
I'm currently using CyberGhost VPN. `~/.vpn` folder stores its OpenVPN config (`openvpn.ovpn`), modified as follows:
- paths to `ca`, `cert` and `key` are made absolute
```vim
ca /home/pavel/.vpn/ca.crt
cert /home/pavel/.vpn/client.crt
key /home/pavel/.vpn/client.key
```
- added `auth-user-pass` with a link to login info
```vim
auth-user-pass /home/pavel/.vpn/auth.conf
```
`auth.conf` looks like this:
```text
login
password
```
- run [openvpn-update-resolv-conf](https://github.com/alfredopalhares/openvpn-update-resolv-conf) script to fix DNS. `openvpn-update-resolve-conf` originates in my [channel-q](https://github.com/SqrtMinusOne/channel-q).
```vim
setenv PATH /home/pavel/.guix-extra-profiles/system/system/bin:/home/pavel/.guix-extra-profiles/system/system/sbin:/home/pavel/.guix-extra-profiles/console/console/bin:/run/current-system/profile/bin:/run/current-system/profile/sbin
up /home/pavel/.guix-extra-profiles/system/system/bin/update-resolv-conf.sh
down /home/pavel/.guix-extra-profiles/system/system/bin/update-resolv-conf.sh
```
`setenv PATH` is necessary because both `resolvconf` (openresolve) and `update-resolv-conf.sh` are shell scripts which need GNU coreutils and stuff, and OpenVPN clears PATH by default.
- run a script to fix Docker routes
```vim
route-up /home/pavel/bin/scripts/vpn-fix-routes
```
References:
- [Github issue](https://github.com/moby/libnetwork/issues/779)
The script itself:
```sh
echo "Adding default route to $route_vpn_gateway with /0 mask..."
IP=/run/current-system/profile/sbin/ip
$IP route add default via $route_vpn_gateway
echo "Removing /1 routes..."
$IP route del 0.0.0.0/1 via $route_vpn_gateway
$IP route del 128.0.0.0/1 via $route_vpn_gateway
```
#### vpn-start {#vpn-start}
As of now, CyberGhost doesn't provide ipv6, so we have to disable it.
```bash
export DISPLAY=:0
CONN=$(nmcli -f NAME con show --active | grep -Ev "(.*docker.*|NAME|br-.*|veth.*|tun.*|vnet.*|virbr.*)" | sed 's/ *$//g')
if [ -z "$CONN" ]; then
echo "No connection!"
notify-send "VPN" "No connection for VPN to run"
exit
fi
echo "Connection: $CONN"
notify-send "VPN" "Initializing for connection: $CONN"
pkexec nmcli con modify "$CONN" ipv6.method ignore
nmcli connection up "$CONN"
pkexec openvpn --config ~/.vpn/openvpn.ovpn
```
#### vpn-stop {#vpn-stop}
Also a script to reverse the changes.
```bash
CONN=$(nmcli -f NAME con show --active | grep -Ev "(.*docker.*|NAME|br-.*|veth.*|tun.*)" | sed 's/ *$//g')
echo "Connection: $CONN"
pkexec nmcli con modify "$CONN" ipv6.method auto
nmcli connection up "$CONN"
```
### flatpak {#flatpak}
As for now, the easiest way to install most of proprietary software is via flatpak. See the relevant section in [Desktop.org]({{< relref "Desktop" >}}).
### conda {#conda}
[conda](https://docs.conda.io/en/latest/) is a package manager, which I use for managing various versions of Python & Node.js.
It is packaged for GNU Guix, although the definition has its fair share of workarounds. It is almost surprising to see it work with all the C libraries and stuff. But there are still some problems.
First, it's impossible to perform `conda init` to patch files like `.bashrc`, because the command is hell-bent on modifying `/gnu/store/`. So I do this manually, look for the `init_conda` procedures in [Console.org]({{< relref "Console" >}}).
Second, base environment root is `/gnu/store`, so don't install anything there.
Third, by default it tries to create envronments in `/gnu/store`. I think it's enough to create one environment like this to fix it:
```sh
mkdir -p ~/.conda/envs
conda create -p ~/.conda/envs/test
```
Finally, I also want to have an ability to use global npm. Some settings for that are located in [Console.org](Console). Here we want to unset `NPM_CONFIG_USERCONFIG` if there is npm available in the environment.
So here is a script to set up conda hooks:
```bash
# Get writable conda envs with npm & without
readarray -t CONDA_ENVS_ALL <<< $(conda env list --json | jq '.envs[]')
CONDA_ENVS_NPM=()
CONDA_ENVS_NO_NPM=()
for env in "${CONDA_ENVS_ALL[@]}"; do
env="${env:1:${#env}-2}"
if [ -w "$env" ]; then
if [ -f "$env/bin/npm" ]; then
CONDA_ENVS_NPM+=($env)
else
CONDA_ENVS_NO_NPM+=($env)
fi
fi
done
for env in "${CONDA_ENVS_NPM[@]}"; do
echo "Found npm in $env"
mkdir -p "$env/etc/conda/activate.d"
mkdir -p "$env/etc/conda/deactivate.d"
echo "unset NPM_CONFIG_USERCONFIG" > "$env/etc/conda/activate.d/conda.sh"
echo "set -e NPM_CONFIG_USERCONFIG" > "$env/etc/conda/activate.d/conda.fish"
echo "export NPM_CONFIG_USERCONFIG=$HOME/._npmrc" > "$env/etc/conda/deactivate.d/conda.sh"
echo "export NPM_CONFIG_USERCONFIG=$HOME/._npmrc" > "$env/etc/conda/deactivate.d/conda.fish"
done
for env in "${CONDA_ENVS_NO_NPM}"; do
echo "Did not found npm in $env"
rm -rf "$env/etc/conda/activate.d/conda.sh" || true
rm -rf "$env/etc/conda/activate.d/conda.fish" || true
rm -rf "$env/etc/conda/deactivate.d/conda.sh" || true
rm -rf "$env/etc/conda/deactivate.d/conda.fish" || true
done
```
### Slack {#slack}
What a nonsense of a program.
I was able to launch the nix version with the following wrapper script:
```bash
export PATH="$HOME/bin/dummies:$PATH"
mkdir -p ~/.cache/slack
slack -r ~/.cache/slack
```
Also, it requires a `lsb_release` in the PATH, so here is one:
```bash
echo "LSB Version: Hey. I spent an hour figuring out why Slack doesn't launch."
echo "Distributor ID: It seems like it requires an lsb_release."
echo "Description: But GNU Guix doesn't have one."
echo "Release: 42.2"
echo "Codename: n/a"
```
### virt-manager {#virt-manager}
Run the following to fix the network:
```sh
sudo virsh net-define /run/current-system/profile/etc/libvirt/qemu/networks/default.xml
sudo virsh net-start default
sudo herd restart libvirtd
```
### wakatime-cli {#wakatime-cli}
| Note | Description |
|------|-----------------------|
| TODO | Package this for Guix |
Before I figure out how to package this for Guix:
- Clone [the repo](https://github.com/wakatime/wakatime-cli)
- Run `go build`
- Copy the binary to the `~/bin` folder
### Manifest {#manifest}
<a id="code-snippet--packages"></a>
```emacs-lisp
(my/format-guix-dependencies category)
```
System
```scheme
(specifications->manifest
'(
<<packages("system")>>))
```

819
content/configs/Guix.md~ Normal file
View file

@ -0,0 +1,819 @@
+++
title = "Guix"
author = ["Pavel"]
draft = false
+++
[GNU Guix](https://guix.gnu.org/) is (1) a transactional package manager and (2) a GNU/Linux distribution.
My personal selling points are declarative package configuration and transactional upgrades.
References:
- [Official help](https://guix.gnu.org/en/help/)
- [System Crafters wiki](https://wiki.systemcrafters.cc/guix)
- [Pjotr Prins' Guix notes](https://gitlab.com/pjotrp/guix-notes)
- [Davil Wilson's YouTube series](https://www.youtube.com/watch?v=iBaqOK75cho&list=PLEoMzSkcN8oNxnj7jm5V2ZcGc52002pQU)
<div class="ox-hugo-toc toc">
<div></div>
<div class="heading">Table of Contents</div>
- [Contents](#contents)
- [Profiles](#profiles)
- [Activate profiles](#activate-profiles)
- [Update profiles](#update-profiles)
- [Channels](#channels)
- [Systems](#systems)
- [Base configuration](#base-configuration)
- [indigo](#indigo)
- [eminence](#eminence)
- [azure](#azure)
- [System installation](#system-installation)
- [Preparation](#preparation)
- [Installation](#installation)
- [After installation](#after-installation)
- [Misc software & notes](#misc-software-and-notes)
- [VPN](#vpn)
- [vpn-start](#vpn-start)
- [vpn-stop](#vpn-stop)
- [flatpak](#flatpak)
- [conda](#conda)
- [Slack](#slack)
- [virt-manager](#virt-manager)
- [wakatime-cli](#wakatime-cli)
- [Manifest](#manifest)
</div>
<!--endtoc-->
## Contents {#contents}
- [Contents](#contents)
- [Profiles](#profiles)
- [Activate profiles](#activate-profiles)
- [Update profiles](#update-profiles)
- [Channels](#channels)
- [Systems](#systems)
- [Base configuration](#base-configuration)
- [indigo](#indigo)
- [eminence](#eminence)
- [azure](#azure)
- [System installation](#system-installation)
- [Preparation](#preparation)
- [Installation](#installation)
- [After installation](#after-installation)
- [Misc software & notes](#misc-software-and-notes)
- [VPN](#vpn)
- [vpn-start](#vpn-start)
- [vpn-stop](#vpn-stop)
- [flatpak](#flatpak)
- [conda](#conda)
- [Slack](#slack)
- [virt-manager](#virt-manager)
- [wakatime-cli](#wakatime-cli)
- [Manifest](#manifest)
## Profiles {#profiles}
A profile is a way to group Guix packages. Amongst its advantages, profiles can be defined by manifests, which in turn can be stored in VCS.
References:
- [Guix Profiles in Practice](https://guix.gnu.org/en/cookbook/en/html%5Fnode/Guix-Profiles-in-Practice.html)
### Activate profiles {#activate-profiles}
A script to activate guix profiles. Usage:
```text
activate-profiles [profile1] [profile2] ...
```
Source: [David Wilson's config](https://github.com/daviwil/dotfiles/blob/master/Systems.org#activating-profiles)
```bash
GREEN='\033[1;32m'
RED='\033[1;30m'
NC='\033[0m'
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
profiles=$*
if [[ $# -eq 0 ]]; then
profiles="$HOME/.config/guix/manifests/*.scm";
fi
for profile in $profiles; do
# Remove the path and file extension, if any
profileName=$(basename $profile)
profileName="${profileName%.*}"
profilePath="$GUIX_EXTRA_PROFILES/$profileName"
manifestPath=$HOME/.config/guix/manifests/$profileName.scm
if [ -f $manifestPath ]; then
echo
echo -e "${GREEN}Activating profile:" $manifestPath "${NC}"
echo
mkdir -p $profilePath
guix package --manifest=$manifestPath --profile="$profilePath/$profileName"
# Source the new profile
GUIX_PROFILE="$profilePath/$profileName"
if [ -f $GUIX_PROFILE/etc/profile ]; then
. "$GUIX_PROFILE"/etc/profile
else
echo -e "${RED}Couldn't find profile:" $GUIX_PROFILE/etc/profile "${NC}"
fi
else
echo "No profile found at path" $profilePath
fi
done
```
### Update profiles {#update-profiles}
A script to update Guix profiles. Usage:
```text
update-profiles [profile1] [profile2] ...
```
Source: once again, [David Wilson's config](https://github.com/daviwil/dotfiles/blob/master/Systems.org#updating-profiles).
```bash
GREEN='\033[1;32m'
NC='\033[0m'
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
profiles=$*
if [[ $# -eq 0 ]]; then
profiles="$GUIX_EXTRA_PROFILES/*";
fi
for profile in $profiles; do
profileName=$(basename $profile)
profilePath=$GUIX_EXTRA_PROFILES/$profileName
echo
echo -e "${GREEN}Updating profile:" $profilePath "${NC}"
echo
guix package --profile="$profilePath/$profileName" --manifest="$HOME/.config/guix/manifests/$profileName.scm"
done
```
## Channels {#channels}
Specifying additional channels.
[channel-q](https://github.com/SqrtMinusOne/channel-q) is my Guix channel. Don't use it at home.
References:
- [nonguix channel repo](https://gitlab.com/nonguix/nonguix)
- [Guix channels reference](https://guix.gnu.org/manual/en/html%5Fnode/Channels.html)
<!--listend-->
```scheme
(cons*
(channel
(name 'channel-q)
(url "file:///home/pavel/Code/channel-q"))
(channel
(name 'flat)
(url "https://github.com/flatwhatson/guix-channel.git")
(introduction
(make-channel-introduction
"33f86a4b48205c0dc19d7c036c85393f0766f806"
(openpgp-fingerprint
"736A C00E 1254 378B A982 7AF6 9DBE 8265 81B6 4490"))))
(channel
(name 'nonguix)
(url "https://gitlab.com/nonguix/nonguix")
;; (commit "d54973e47b89fe5772a5b6e2d0c0b86acb089e27")
(introduction
(make-channel-introduction
"897c1a470da759236cc11798f4e0a5f7d4d59fbc"
(openpgp-fingerprint
"2A39 3FFF 68F4 EF7A 3D29 12AF 6F51 20A0 22FB B2D5"))))
%default-channels)
```
## Systems {#systems}
Configuring systems with Guix.
Yes, all my machines are named after colors I like.
### Base configuration {#base-configuration}
The base configuration is shared between all the machines.
While it's possible to make a single `.scm` file with base configuration and load it, I noticed that it produces more cryptic error messages whenever there is an error in the base file, so I opt-in for noweb.
`guix system` invocation is as follows:
```text
sudo -E guix system reconfigure ~/.config/guix/systems/[system].scm
```
Common modules:
```scheme
(use-modules (gnu))
(use-modules (gnu system nss))
(use-modules (gnu packages bash))
(use-modules ((gnu packages base) #:select (coreutils glibc)))
(use-modules (gnu packages certs))
(use-modules (gnu packages version-control))
(use-modules (gnu packages vim))
(use-modules (gnu packages gnome))
(use-modules (gnu packages xorg))
(use-modules (gnu packages wm))
(use-modules (gnu packages openbox))
(use-modules (gnu services docker))
(use-modules (gnu services cups))
(use-modules (gnu services virtualization))
(use-modules (srfi srfi-1))
(use-modules (guix channels))
(use-modules (guix inferior))
(use-modules (nongnu packages linux))
(use-modules (nongnu system linux-initrd))
(use-service-modules desktop networking ssh xorg nix)
(use-package-modules ssh)
```
In principle, we could define a variable called `base-operating-system` and extend it in ancestors. However, then we would have to define mandatory fields like `host-name`, `bootloader` with dummy values. Since I'm already using noweb, there is little point.
The following code will be inserted at the top of the `operating-system` definition.
Use the full Linux kernel. I hope I'll be able to use Libre kernel somewhere later.
Inferior in the kernel is used to avoid recompilation. It looks like I can pin these to different commits than in my `channels.scm`
```scheme
(kernel
(let*
((channels
(list (channel
(name 'nonguix)
(url "https://gitlab.com/nonguix/nonguix")
(commit "d3c5eea0cbfe3e5bfbcf1fe15bc916fefacc624f"))
(channel
(name 'guix)
(url "https://git.savannah.gnu.org/git/guix.git")
(commit "cf88c967afbf15c58efb0ba37d6638f1be9a0481"))))
(inferior
(inferior-for-channels channels)))
(first (lookup-inferior-packages inferior "linux" "5.12.9"))))
;; (kernel linux)
(initrd microcode-initrd)
(firmware (list linux-firmware))
(locale "en_US.utf8")
(timezone "Europe/Moscow")
```
US/RU keyboard layout, switch with Alt+Shift.
```scheme
(keyboard-layout (keyboard-layout "us,ru" #:options '("grp:alt_shift_toggle")))
```
User accounts.
```scheme
(users (cons* (user-account
(name "pavel")
(comment "Pavel")
(group "users")
(home-directory "/home/pavel")
(supplementary-groups
'("wheel" ;; sudo
"netdev" ;; network devices
"audio"
"video"
"input"
"tty"
"docker"
"scanner"
"libvirt"
"lp")))
%base-user-accounts))
```
Base packages, necessary right after the installation.
```scheme
(packages
(append
(list nss-certs
git
i3-gaps
i3lock
openbox
xterm
vim)
%base-packages))
```
Default services for each machine:
- override the default `%desktop-services` to add OpenVPN support
- add nix service
- add docker service
- add CUPS service
- add libvirt service
- add a symlink to ELF interpreter to where most Linux binaries expect it
<!--listend-->
```scheme
(define %my-base-services
(cons*
(service openssh-service-type)
(screen-locker-service i3lock "i3lock")
(extra-special-file "/lib64/ld-linux-x86-64.so.2" (file-append glibc "/lib/ld-linux-x86-64.so.2"))
(service nix-service-type)
(service cups-service-type
(cups-configuration
(web-interface? #t)))
(service docker-service-type)
(service libvirt-service-type
(libvirt-configuration
(unix-sock-group "libvirt")
(tls-port "16555")))
(service virtlog-service-type)
(modify-services %desktop-services
(network-manager-service-type
config =>
(network-manager-configuration
(inherit config)
(vpn-plugins (list network-manager-openvpn)))))))
```
### indigo {#indigo}
`indigo` is my desktop PC.
```scheme
<<system-common>>
(operating-system
<<system-base>>
(host-name "indigo")
(services (cons*
(set-xorg-configuration
(xorg-configuration
(keyboard-layout keyboard-layout)))
%my-base-services))
(bootloader
(bootloader-configuration
(bootloader grub-efi-bootloader)
(target "/boot/efi")
(keyboard-layout keyboard-layout)))
(swap-devices
(list (uuid "059a2c26-8f70-4986-adf0-1a2e7b511404")))
(file-systems
(cons* (file-system
(mount-point "/")
(device (file-system-label "my-root"))
(type "ext4"))
(file-system
(mount-point "/boot/efi")
(device "/dev/sda1")
(type "vfat"))
%base-file-systems)))
```
### eminence {#eminence}
`eminence` is a HP 15s laptop.
`%backlight-udev-rule` should enable members of `video` group change the display backlight. See the relevant page at [Arch Wiki](https://wiki.archlinux.org/title/Backlight).
```scheme
<<system-common>>
(define %backlight-udev-rule
(udev-rule
"90-backlight.rules"
(string-append "ACTION==\"add\", SUBSYSTEM==\"backlight\", "
"RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""
"\n"
"ACTION==\"add\", SUBSYSTEM==\"backlight\", "
"RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\"")))
(operating-system
<<system-base>>
(host-name "eminence")
(services (cons*
(set-xorg-configuration
(xorg-configuration
(keyboard-layout keyboard-layout)))
(modify-services %my-base-services
(elogind-service-type
config =>
(elogind-configuration
(inherit config)
(handle-lid-switch-external-power 'suspend)))
(udev-service-type
config =>
(udev-configuration
(inherit config)
(rules (cons %backlight-udev-rule
(udev-configuration-rules config))))))))
(bootloader
(bootloader-configuration
(bootloader grub-efi-bootloader)
(target "/boot/efi")
(keyboard-layout keyboard-layout)))
(swap-devices
(list (uuid "f93cf3f6-7ee7-42ec-8ee2-f3d896fdf9b5")))
(file-systems
(cons* (file-system
(mount-point "/")
(device
(uuid "1d937704-bbeb-43b5-bc63-453886c426af"
'ext4))
(type "ext4"))
(file-system
(mount-point "/boot/efi")
(device (uuid "0031-3784" 'fat32))
(type "vfat"))
%base-file-systems)))
```
### azure {#azure}
`azure` is a Lenovo Ideapad 330 laptop.
`%backlight-udev-rule` should enable members of `video` group change the display backlight. See the relevant page at [Arch Wiki](https://wiki.archlinux.org/title/Backlight).
```scheme
<<system-common>>
(define %backlight-udev-rule
(udev-rule
"90-backlight.rules"
(string-append "ACTION==\"add\", SUBSYSTEM==\"backlight\", "
"RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""
"\n"
"ACTION==\"add\", SUBSYSTEM==\"backlight\", "
"RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\"")))
(operating-system
<<system-base>>
(host-name "azure")
(services (cons*
(set-xorg-configuration
(xorg-configuration
(keyboard-layout keyboard-layout)))
(modify-services %my-base-services
(elogind-service-type config =>
(elogind-configuration (inherit config)
(handle-lid-switch-external-power 'suspend)))
(udev-service-type config =>
(udev-configuration (inherit config)
(rules (cons %backlight-udev-rule
(udev-configuration-rules config))))))))
(bootloader
(bootloader-configuration
(bootloader grub-efi-bootloader)
(target "/boot/efi")
(keyboard-layout keyboard-layout)))
(swap-devices
(list (uuid "4b2dedb3-b111-4e69-8c05-6daa2b072c76")))
(file-systems
(cons* (file-system
(mount-point "/")
(device (file-system-label "my-root"))
(type "ext4"))
(file-system
(mount-point "/boot/efi")
(device "/dev/sda1")
(type "vfat"))
%base-file-systems)))
```
## System installation {#system-installation}
### Preparation {#preparation}
In my case, the provided ISO doesn't work because of the Libre kernel.
Fortunately, David Wilson has made [a repository](https://github.com/SystemCrafters/guix-installer) with a toolchain to make an ISO with the full kernel. In case it won't be an option, the [nonguix repo](https://gitlab.com/nonguix/nonguix) also has instructions on how to do that.
When an ISO is there, we have to write it on a USB stick. Run `sudo fdisk -l` to get a list of disks.
The approach in the official instruction is to create a bootable USB with `dd`:
```text
sudo dd of=/dev/sdxX if=<path-to-iso> status=progress && sync
```
However, I couldn't make it work for some strange reason. Fortunately, `gnome-disk-utility` was able to produce a bootable USB.
### Installation {#installation}
Going further, the official instructions for installation & SystemCrafters wiki entry are pretty good, so it's not necessary to repeat them here.
### After installation {#after-installation}
After the installation, the strategy is as follows.
Set a password for the main user (pavel). Login with openbox to get a tolerable interface because the i3 default config is horrible.
[Connect to the internet](https://guix.gnu.org/en/manual/en/html%5Fnode/Keyboard-Layout-and-Networking-and-Partitioning.html#Keyboard-Layout-and-Networking-and-Partitioning).
Clone the dotfiles repo:
```text
mkdir Code
cd Code
git clone https://github.com/SqrtMinusOne/dotfiles.git
```
Copy the channels file and run guix pull:
```text
cp ~/Code/dotfiles/.config/guix/channels.scm ~/.config/guix
guix pull
```
The first pull usually takes a while. After that install yadm and pull dotfiles:
```text
guix install yadm
guix clone https://github.com/SqrtMinusOne/dotfiles.git
```
And activate the required profiles. Again, downloading & building Emacs, Starship and stuff will take a while.
Don't forget to install `JetBrainsMono Nerd Font`.
## Misc software & notes {#misc-software-and-notes}
| Category | Guix dependency | Description |
|----------|-----------------|----------------------------------------------------|
| system | patchelf | A program to modify existsing ELF executables |
| system | glibc | A lot of stuff, including ELF interpeter and `ldd` |
### VPN {#vpn}
| Category | Guix dependency |
|----------|-----------------------------|
| system | openvpn |
| system | openvpn-update-resolve-conf |
I'm not sure how to properly spin up VPN on Guix, so here is what I'm doing now, after some trial and error.
I'm currently using CyberGhost VPN. `~/.vpn` folder stores its OpenVPN config (`openvpn.ovpn`), modified as follows:
- paths to `ca`, `cert` and `key` are made absolute
```vim
ca /home/pavel/.vpn/ca.crt
cert /home/pavel/.vpn/client.crt
key /home/pavel/.vpn/client.key
```
- added `auth-user-pass` with a link to login info
```vim
auth-user-pass /home/pavel/.vpn/auth.conf
```
`auth.conf` looks like this:
```text
login
password
```
- run [openvpn-update-resolv-conf](https://github.com/alfredopalhares/openvpn-update-resolv-conf) script to fix DNS. `openvpn-update-resolve-conf` originates in my [channel-q](https://github.com/SqrtMinusOne/channel-q).
```vim
setenv PATH /home/pavel/.guix-extra-profiles/system/system/bin:/home/pavel/.guix-extra-profiles/system/system/sbin:/home/pavel/.guix-extra-profiles/console/console/bin:/run/current-system/profile/bin:/run/current-system/profile/sbin
up /home/pavel/.guix-extra-profiles/system/system/bin/update-resolv-conf.sh
down /home/pavel/.guix-extra-profiles/system/system/bin/update-resolv-conf.sh
```
`setenv PATH` is necessary because both `resolvconf` (openresolve) and `update-resolv-conf.sh` are shell scripts which need GNU coreutils and stuff, and OpenVPN clears PATH by default.
- run a script to fix Docker routes
```vim
route-up /home/pavel/bin/scripts/vpn-fix-routes
```
References:
- [Github issue](https://github.com/moby/libnetwork/issues/779)
The script itself:
```sh
echo "Adding default route to $route_vpn_gateway with /0 mask..."
IP=/run/current-system/profile/sbin/ip
$IP route add default via $route_vpn_gateway
echo "Removing /1 routes..."
$IP route del 0.0.0.0/1 via $route_vpn_gateway
$IP route del 128.0.0.0/1 via $route_vpn_gateway
```
#### vpn-start {#vpn-start}
As of now, CyberGhost doesn't provide ipv6, so we have to disable it.
```bash
export DISPLAY=:0
CONN=$(nmcli -f NAME con show --active | grep -Ev "(.*docker.*|NAME|br-.*|veth.*|tun.*|vnet.*|virbr.*)" | sed 's/ *$//g')
if [ -z "$CONN" ]; then
echo "No connection!"
notify-send "VPN" "No connection for VPN to run"
exit
fi
echo "Connection: $CONN"
notify-send "VPN" "Initializing for connection: $CONN"
pkexec nmcli con modify "$CONN" ipv6.method ignore
nmcli connection up "$CONN"
pkexec openvpn --config ~/.vpn/openvpn.ovpn
```
#### vpn-stop {#vpn-stop}
Also a script to reverse the changes.
```bash
CONN=$(nmcli -f NAME con show --active | grep -Ev "(.*docker.*|NAME|br-.*|veth.*|tun.*)" | sed 's/ *$//g')
echo "Connection: $CONN"
pkexec nmcli con modify "$CONN" ipv6.method auto
nmcli connection up "$CONN"
```
### flatpak {#flatpak}
As for now, the easiest way to install most of proprietary software is via flatpak. See the relevant section in [Desktop.org]({{< relref "Desktop" >}}).
### conda {#conda}
[conda](https://docs.conda.io/en/latest/) is a package manager, which I use for managing various versions of Python & Node.js.
It is packaged for GNU Guix, although the definition has its fair share of workarounds. It is almost surprising to see it work with all the C libraries and stuff. But there are still some problems.
First, it's impossible to perform `conda init` to patch files like `.bashrc`, because the command is hell-bent on modifying `/gnu/store/`. So I do this manually, look for the `init_conda` procedures in [Console.org]({{< relref "Console" >}}).
Second, base environment root is `/gnu/store`, so don't install anything there.
Third, by default it tries to create envronments in `/gnu/store`. I think it's enough to create one environment like this to fix it:
```sh
mkdir -p ~/.conda/envs
conda create -p ~/.conda/envs/test
```
Finally, I also want to have an ability to use global npm. Some settings for that are located in [Console.org](Console). Here we want to unset `NPM_CONFIG_USERCONFIG` if there is npm available in the environment.
So here is a script to set up conda hooks:
```bash
# Get writable conda envs with npm & without
readarray -t CONDA_ENVS_ALL <<< $(conda env list --json | jq '.envs[]')
CONDA_ENVS_NPM=()
CONDA_ENVS_NO_NPM=()
for env in "${CONDA_ENVS_ALL[@]}"; do
env="${env:1:${#env}-2}"
if [ -w "$env" ]; then
if [ -f "$env/bin/npm" ]; then
CONDA_ENVS_NPM+=($env)
else
CONDA_ENVS_NO_NPM+=($env)
fi
fi
done
for env in "${CONDA_ENVS_NPM[@]}"; do
echo "Found npm in $env"
mkdir -p "$env/etc/conda/activate.d"
mkdir -p "$env/etc/conda/deactivate.d"
echo "unset NPM_CONFIG_USERCONFIG" > "$env/etc/conda/activate.d/conda.sh"
echo "set -e NPM_CONFIG_USERCONFIG" > "$env/etc/conda/activate.d/conda.fish"
echo "export NPM_CONFIG_USERCONFIG=$HOME/._npmrc" > "$env/etc/conda/deactivate.d/conda.sh"
echo "export NPM_CONFIG_USERCONFIG=$HOME/._npmrc" > "$env/etc/conda/deactivate.d/conda.fish"
done
for env in "${CONDA_ENVS_NO_NPM}"; do
echo "Did not found npm in $env"
rm -rf "$env/etc/conda/activate.d/conda.sh" || true
rm -rf "$env/etc/conda/activate.d/conda.fish" || true
rm -rf "$env/etc/conda/deactivate.d/conda.sh" || true
rm -rf "$env/etc/conda/deactivate.d/conda.fish" || true
done
```
### Slack {#slack}
What a nonsense of a program.
I was able to launch the nix version with the following wrapper script:
```bash
export PATH="$HOME/bin/dummies:$PATH"
mkdir -p ~/.cache/slack
slack -r ~/.cache/slack
```
Also, it requires a `lsb_release` in the PATH, so here is one:
```bash
echo "LSB Version: Hey. I spent an hour figuring out why Slack doesn't launch."
echo "Distributor ID: It seems like it requires an lsb_release."
echo "Description: But GNU Guix doesn't have one."
echo "Release: 42.2"
echo "Codename: n/a"
```
### virt-manager {#virt-manager}
Run the following to fix the network:
```sh
sudo virsh net-define /run/current-system/profile/etc/libvirt/qemu/networks/default.xml
sudo virsh net-start default
sudo herd restart libvirtd
```
### wakatime-cli {#wakatime-cli}
| Note | Description |
|------|-----------------------|
| TODO | Package this for Guix |
Before I figure out how to package this for Guix:
- Clone [the repo](https://github.com/wakatime/wakatime-cli)
- Run `go build`
- Copy the binary to the `~/bin` folder
### Manifest {#manifest}
<a id="code-snippet--packages"></a>
```emacs-lisp
(my/format-guix-dependencies category)
```
System
```scheme
(specifications->manifest
'(
<<packages("system")>>))
```

582
content/configs/Mail.md Normal file
View file

@ -0,0 +1,582 @@
+++
title = "Mail"
author = ["Pavel"]
draft = false
+++
My email configration. Currently uses [lieer](https://github.com/gauteh/lieer) to fetch emails from Gmail, [davmail](http://davmail.sourceforge.net/) & [offlineimap](http://www.offlineimap.org/) to fetch emails from MS Exchange, [notmuch](https://notmuchmail.org/) to index, [msmtp](https://marlam.de/msmtp/) to send emails. Also using notmuch frontend from Emacs.
My problem with any particular mail setup was that I use Gmail labels quite extensively, and handling these over IMAP is rather awkward. Notmuch seems to be the only software that provides the same first-class support for labels.
But I also have an Exchange account, with which I communicate via IMAP/SMTP adapter, and in this case, I synchronize notmuch tags and IMAP folders.
References:
- [My post](https://sqrtminusone.xyz/posts/2021-02-27-gmail/) about email configuration. I wrote it some time ago, but the general idea remains.
<div class="ox-hugo-toc toc">
<div></div>
<div class="heading">Table of Contents</div>
- [Lieer](#lieer)
- [DavMail](#davmail)
- [OfflineIMAP](#offlineimap)
- [Notmuch](#notmuch)
- [Config](#config)
- [Hooks](#hooks)
- [`pre_new`](#pre-new)
- [`post_new`](#post-new)
- [Sync script](#sync-script)
- [MSMTP](#msmtp)
- [Emacs](#emacs)
- [Saved filters and keybindings](#saved-filters-and-keybindings)
- [Signing messages](#signing-messages)
- [mailcap](#mailcap)
- [Guix settings](#guix-settings)
</div>
<!--endtoc-->
## Lieer {#lieer}
| Guix dependency |
|-----------------|
| python-lieer |
Lieer is a program to link up Gmail and notmuch. Basically, it downloads mail from Gmail via API, stores them in Maildir, and synchronizes labels with notmuch.
I have a separate directory in my `~/Mail` for each address. To init lieer, run the following command in the directory:
```text
gmi init <address>
```
After which the settings will be stored in `gmailieer.json` and the credentials in `.credentials.gmailieer.json`. The latter file is stored encrypted.
My preferred settings:
```text
gmi set --replace-slash-with-dot
gmi set --ignore-tags-local new
```
Running `gmi sync` in the required directory performs the synchronization. The first sync takes a while, the subsequent syncs are pretty fast.
## DavMail {#davmail}
is a gateway between MS Exchange and the rest of the world, which uses IMAP/SMTP/LDAP/etc. As I have one corporate MS Exchange address, this is just the program I need. As of yet, it isn't packaged for Guix, but it's easy enough to download.
It has a GUI mode, but I prefer headless config.
```ini
davmail.server=true
davmail.mode=Auto
davmail.url=https://mail.etu.ru/owa/
davmail.caldavPort=1080
davmail.imapPort=1143
davmail.ldapPort=1389
davmail.popPort=1110
davmail.smtpPort=1025
davmail.imapAutoExpunge=false
davmail.enableKeepalive=false
```
Also it's a bit of problem to get it launched as it looks for some jars in pwd, so here is a script.
```bash
cd $HOME/bin/davmail-6.0.0-3375
./davmail davmail.properties
```
Shepherd service is defined in [Desktop.org]({{< relref "Desktop" >}}).
## OfflineIMAP {#offlineimap}
| Guix dependency |
|-----------------|
| offlineimap |
[OfflineIMAP](https://github.com/OfflineIMAP/offlineimap) is a program that can synchronize IMAP mailbox and Maildir. Lieer does everything by itself, but my pirate Exchange IMAP needs this program. There is also [isync](https://isync.sourceforge.io/), but I had some weird issues with duplicate UIDs, which don't occur for OfflineIMAP.
I have a few options for setting a username and password. First, I can run `pass` in `remotepasswordeval`, and this is fine, but it will keep by keyring unlocked because I want to run `offlineimap` every couple of minutes.
Another option is to use noweb and not push the file below to the version control. Then I have a plaintext password of email on my computer, but I think it's a lesser evil than the entire keyring.
I would use `password-store-get` from password-store.el, but I want this to be able to run without any 3rd party packages, so it's just bash.
<a id="code-snippet--mail-username"></a>
```bash
pass show Job/Infrastructure/pvkorytov@etu.ru | sed -n 's/username: //;2p'
```
<a id="code-snippet--mail-password"></a>
```bash
pass show Job/Infrastructure/pvkorytov@etu.ru | head -n 1
```
```ini
[general]
accounts = pvkorytov
[Account pvkorytov]
localrepository = pvkorytov-local
remoterepository = pvkorytov-remote
[Repository pvkorytov-local]
type = Maildir
localfolders = ~/Mail/pvkorytov_etu/
[Repository pvkorytov-remote]
type = IMAP
remotehost = localhost
remoteuser = <<mail-username()>>
remotepass = <<mail-password()>>
remoteport = 1143
starttls = no
ssl = no
```
## Notmuch {#notmuch}
| Guix dependency |
|-----------------|
| notmuch |
| parallel |
Notmuch is an email indexer program, which handles labels in a way somewhat like Gmail. It also provides a frontend for Emacs, but it's not the only one available.
### Config {#config}
Not much is going on here.
First, the database path.
```ini
[database]
path=/home/pavel/Mail
```
My name and list of emails. It's not like it's a secret anyhow.
```ini
[user]
name=Pavel Korytov
primary_email=thexcloud@gmail.com
other_email=progin6304@gmail.com;pvkorytov@etu.ru
```
A list of tags which will be added by `notmuch new` and directory names which will be ignored by `notmuch new`.
```ini
[new]
tags=new;
ignore=.osync_workdir;.mbsyncstate;.uidvalidity;.lock;/.*gmailieer\.json.*/
```
Exclude these tags from search by default.
```ini
[search]
exclude_tags=trash;spam;
```
Maildir compatibility.
```ini
[maildir]
synchronize_flags=true
```
### Hooks {#hooks}
Now we have to link up lieer & Maildir and with notmuch. This is done via the notmuch hook system, which allows running custom scripts before and after any command.
With lieer and Gmail, it is enough to simply run the program, because Gmail has first-class support for tags. Maildir does not, so I decide to synchronize notmuch tags and IMAP folders. In essence, the idea is to:
- move emails to their folders by tags _before_ the synchronization
- tag mails by their folders _after_ the synchronization
The problem is that with that approach one email can have only one tag, but it's better than nothing.
So, here are the rules which match tags & folders:
<a id="table--pvkorytov-tags"></a>
| tag | folder |
|--------------------------|---------------------------|
| inbox | INBOX |
| sent | Sent |
| spam | Junk |
| trash | Trash |
| job.digital | Job\_Digital |
| job.digital.docs | Job\_Digital.Docs |
| job.digital.support | Job\_Digital.Support |
| job.digital.superservice | Job\_Digital.Superservice |
And below is a noweb function, which generates the following commands for notmuch to execute:
- _before_ sync:
- `notmuch search --output files "NOT path:[PATH] AND tag:[TAG] AND tag:[ROOT_TAG]" | xargs -I ! mv ! [PATH]`
Move emails with `TAG` but outside the matching `PATH` to the latter
- `notmuch search --output=files "NOT path:[ARCHIVE_PATH] AND tag:[ROOT_TAG] AND NOT tag:[TAG1] ... AND NOT tag:[TAGN]" | xargs -I ! mv ! [ARCHIVE_PATH]`
Move untagged emails to the `ARCHIVE_PATH`
- _after_ sync:
- `notmuch tag +[TAG] "path:[PATH] AND NOT tag:[TAG]"`
Tag emails in `PATH` which do not yet have the matching `TAG`
- `notmuch tag -[TAG] "NOT path:[PATH] AND tag:[TAG] AND tag:[ROOT_TAG]"`
Remove `TAG` from emails which are outside the matching `PATH`
These rules are getting included in the respective hooks.
<a id="code-snippet--mail-tags"></a>
```emacs-lisp
(setq my/maildir-root "~/Mail")
(let ((rules '()))
(dolist (row tags)
(let ((tag (nth 0 row))
(folder (nth 1 row)))
(unless (string-empty-p make_tag)
(add-to-list
'rules
(format "notmuch tag +%s \"path:%s/%s/cur/** AND NOT tag:%s\""
tag root folder tag)
t))
(unless (string-empty-p remove)
(add-to-list
'rules
(format "notmuch tag -%s \"NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\""
tag root folder tag root_tag)
t))
(unless (string-empty-p move)
(add-to-list
'rules
(concat
(format "notmuch search --output=files \"NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\""
root folder tag root_tag)
(format " | xargs -I ! mv ! %s/%s/%s/cur/" my/maildir-root root folder))
t))))
(unless (string-empty-p archive_root)
(add-to-list
'rules
(concat
(format "notmuch search --output=files \"NOT path:%s/%s/cur/** AND %s AND tag:%s\""
root archive_root
(mapconcat
(lambda (row)
(format "NOT tag:%s" (car row)))
tags
" AND ")
root_tag)
(format " | xargs -I ! mv ! %s/%s/%s/cur/" my/maildir-root root archive_root))
t))
(string-join rules "\n"))
```
#### `pre_new` {#pre-new}
This hook runs fetch from Gmail & offlineimap in parallel before the `notmuch new` command. The `parallel` command is provided by [GNU Parallel](https://www.gnu.org/software/parallel/).
It isn't necessary to run `cd` for offlineimap, but it's easier to write that way.
<a id="code-snippet--pre-new-pvkorytov-tags"></a>
```emacs-lisp
(my/mail-format-tags-rules tags "pvkorytov_etu" "pvkorytov" nil nil t "Archive")
```
```bash
# GMI="/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"
GMI="gmi"
echo "Running pre-new filters"
<<mail-tags(move="t",archive_root="Archive")>>
echo "Pre-new filters done"
parallel --link -j0 "(cd /home/pavel/Mail/{1}/ && {2} {3})" ::: thexcloud progin6304 pvkorytov_etu ::: "$GMI" "$GMI" "offlineimap" ::: sync sync ""
```
#### `post_new` {#post-new}
And this hook tags different mailboxes with different tags.
<a id="code-snippet--post-new-pvkorytov-tags"></a>
```emacs-lisp
(my/mail-format-tags-rules tags "pvkorytov_etu" "pvkorytov" t t)
```
```bash
notmuch tag +main "path:thexcloud/** AND tag:new"
notmuch tag +progin "path:progin6304/** AND tag:new"
notmuch tag +pvkorytov "path:pvkorytov_etu/** AND tag:new"
echo "Running post-new filters"
<<mail-tags(make_tag="t",remove="t")>>
echo "Post-new filters done"
notmuch tag -new "tag:new"
```
## Sync script {#sync-script}
A script to run `notmuch new` and push a notification if there is new mail.
```bash
export DISPLAY=:0
CHECK_FILE="/home/pavel/Mail/.last_check"
QUERY="tag:unread"
ALL_QUERY="tag:unread"
if [ -f "$CHECK_FILE" ]; then
DATE=$(cat "$CHECK_FILE")
QUERY="$QUERY and date:@$DATE.."
fi
notmuch new
NEW_UNREAD=$(notmuch count "$QUERY")
ALL_UNREAD=$(notmuch count "$ALL_QUERY")
if [ $NEW_UNREAD -gt 0 ]; then
MAIN_UNREAD=$(notmuch count "tag:unread AND tag:main")
PROGIN_UNREAD=$(notmuch count "tag:unread AND tag:progin")
ETU_UNREAD=$(notmuch count "tag:unread AND tag:pvkorytov")
read -r -d '' NOTIFICATION <<EOM
$NEW_UNREAD new messages
$MAIN_UNREAD thexcloud@gmail.com
$PROGIN_UNREAD progin6304@gmail.com
$ETU_UNREAD pvkorytov@etu.ru
$ALL_UNREAD total
EOM
notify-send "New Mail" "$NOTIFICATION"
fi
echo "$(date +%s)" > $CHECK_FILE
```
The script is ran via GNU Mcron every 5 minutes.
```scheme
(job "*/5 * * * * " "~/bin/scripts/check-email")
```
## MSMTP {#msmtp}
| Guix dependency |
|-----------------|
| msmtp |
Sending emails can be done with MSMTP. It automatially chooses the email address and server based on the contents of the message, which is handy if there are multiple mailboxes to be managed.
```vim
defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ~/.msmtp.log
account main
host smtp.gmail.com
port 587
from thexcloud@gmail.com
user thexcloud@gmail.com
passwordeval "pass show My_Online/APIs/google-main-app-password | head -n 1"
account progin
host smtp.gmail.com
port 587
from progin6304@gmail.com
user progin6304@gmail.com
passwordeval "pass show My_Online/ETU/progin6304@gmail.com | head -n 1"
account pvkorytov
tls off
auth plain
host localhost
port 1025
from pvkorytov@etu.ru
user pvkorytov
passwordeval "pass show Job/Infrastructure/pvkorytov@etu.ru | head -n 1"
```
## Emacs {#emacs}
Finally, Emacs configuration. Let's start with some variables:
```emacs-lisp
(setq user-mail-address "thexcloud@gmail.com")
(setq user-full-name "Pavel Korytov")
```
Then, the problem with my Guix setup is that Emacs by default doesn't see the elisp files of notmuch, so here is a small workaround:
```emacs-lisp
(let ((default-directory "/home/pavel/.guix-extra-profiles/mail/mail/share/emacs/site-lisp"))
(normal-top-level-add-subdirs-to-load-path))
```
Finally the proper notmuch settings:
```emacs-lisp
(use-package notmuch
;; :ensure nil
:commands (notmuch notmuch-search)
:config
(setq mail-specify-envelope-from t)
(setq message-sendmail-envelope-from 'header)
(setq mail-envelope-from 'header)
(setq notmuch-always-prompt-for-sender t)
(setq sendmail-program (executable-find "msmtp"))
(setq send-mail-function #'sendmail-send-it)
(setq mml-secure-openpgp-sign-with-sender t)
(setq notmuch-mua-user-agent-function 'notmuch-mua-user-agent-full)
(add-hook 'notmuch-hello-mode-hook
(lambda () (display-line-numbers-mode 0))))
```
The file to which this is tangled is read in the init.el.
### Saved filters and keybindings {#saved-filters-and-keybindings}
I want to have the saved filters available in both notmuch interface as as keybindings. So a bit more of abusing org tables.
Root keybindings:
```emacs-lisp
(my-leader-def
:infix "am"
"" '(:which-key "notmuch")
"m" 'notmuch)
```
<a id="table--root-tags"></a>
| Root tag | Prefix | Keybinding description |
|-----------|--------|------------------------|
| main | t | thexcloud@gmail.com |
| progin | p | progin6304@gmail.com |
| pvkorytov | e | pvkorytov@etu.ru |
<a id="table--filter-tags"></a>
| Tag | Prefix | Name |
|--------|--------|----------|
| inbox | i | inbox |
| unread | u | unread |
| sent | s | sent |
| | a | all mail |
The following formats the tables above to a proper syntax for `setq notmuch-saved-searches`:
<a id="code-snippet--format-notmuch-saved-searches"></a>
```emacs-lisp
(let ((searches '()))
(dolist (root_tag root_tags)
(dolist (tag filter_tags)
(add-to-list
'searches
(format "(:name \"%s\" :query \"%s\")"
(format "%s (%s)"
(nth 0 root_tag)
(nth 2 tag))
(concat "tag:" (nth 0 root_tag)
(unless (string-empty-p (nth 0 tag))
(concat " AND tag:" (nth 0 tag)))))
t)))
(string-join searches "\n"))
```
And the following does the same for my general.el definer:
<a id="code-snippet--format-notmuch-keybindings"></a>
```emacs-lisp
(let ((bindings '()))
(dolist (root_tag root_tags)
(add-to-list
'bindings
(format "\"%s\" '(:which-key \"%s\")"
(nth 1 root_tag)
(nth 2 root_tag))
t)
(dolist (tag filter_tags)
(add-to-list
'bindings
(format "\"%s\" '((lambda () (interactive) (notmuch-search \"%s\")) :which-key \"%s\")"
(concat (nth 1 root_tag) (nth 1 tag))
(concat "tag:" (nth 0 root_tag)
(unless (string-empty-p (nth 0 tag))
(concat " AND tag:" (nth 0 tag))))
(nth 2 tag))
t)))
(string-join bindings "\n"))
```
```emacs-lisp
(setq notmuch-saved-searches
'((:name "drafts" :query "tag:draft")
<<format-notmuch-saved-searches()>>))
(my-leader-def
:infix "am"
<<format-notmuch-keybindings()>>)
```
### Signing messages {#signing-messages}
```emacs-lisp
(with-eval-after-load 'notmuch
(add-hook 'message-setup-hook 'mml-secure-sign-pgpmime))
(setq mml-secure-key-preferences
'((OpenPGP
(sign
("thexcloud@gmail.com" "914472A1FD6775C166F96EBEED739ADF81C78160"))
(encrypt))
(CMS
(sign)
(encrypt))))
```
## mailcap {#mailcap}
mailcap file is a file which defines how to read to different MIME types. Notmuch also uses it, so why not keep it here.
```text
audio/*; mpc add %s
image/*; feh %s
application/msword; /usr/bin/xdg-open %s
application/pdf; zathura %s
application/postscript ; zathura %s
text/html; firefox %s
```
## Guix settings {#guix-settings}
<a id="code-snippet--packages"></a>
```emacs-lisp
(my/format-guix-dependencies)
```
```scheme
(specifications->manifest
'(
<<packages()>>))
```

582
content/configs/Mail.md~ Normal file
View file

@ -0,0 +1,582 @@
+++
title = "Mail"
author = ["Pavel"]
draft = false
+++
My email configration. Currently uses [lieer](https://github.com/gauteh/lieer) to fetch emails from Gmail, [davmail](http://davmail.sourceforge.net/) & [offlineimap](http://www.offlineimap.org/) to fetch emails from MS Exchange, [notmuch](https://notmuchmail.org/) to index, [msmtp](https://marlam.de/msmtp/) to send emails. Also using notmuch frontend from Emacs.
My problem with any particular mail setup was that I use Gmail labels quite extensively, and handling these over IMAP is rather awkward. Notmuch seems to be the only software that provides the same first-class support for labels.
But I also have an Exchange account, with which I communicate via IMAP/SMTP adapter, and in this case, I synchronize notmuch tags and IMAP folders.
References:
- [My post](https://sqrtminusone.xyz/posts/2021-02-27-gmail/) about email configuration. I wrote it some time ago, but the general idea remains.
<div class="ox-hugo-toc toc">
<div></div>
<div class="heading">Table of Contents</div>
- [Lieer](#lieer)
- [DavMail](#davmail)
- [OfflineIMAP](#offlineimap)
- [Notmuch](#notmuch)
- [Config](#config)
- [Hooks](#hooks)
- [`pre_new`](#pre-new)
- [`post_new`](#post-new)
- [Sync script](#sync-script)
- [MSMTP](#msmtp)
- [Emacs](#emacs)
- [Saved filters and keybindings](#saved-filters-and-keybindings)
- [Signing messages](#signing-messages)
- [mailcap](#mailcap)
- [Guix settings](#guix-settings)
</div>
<!--endtoc-->
## Lieer {#lieer}
| Guix dependency |
|-----------------|
| python-lieer |
Lieer is a program to link up Gmail and notmuch. Basically, it downloads mail from Gmail via API, stores them in Maildir, and synchronizes labels with notmuch.
I have a separate directory in my `~/Mail` for each address. To init lieer, run the following command in the directory:
```text
gmi init <address>
```
After which the settings will be stored in `gmailieer.json` and the credentials in `.credentials.gmailieer.json`. The latter file is stored encrypted.
My preferred settings:
```text
gmi set --replace-slash-with-dot
gmi set --ignore-tags-local new
```
Running `gmi sync` in the required directory performs the synchronization. The first sync takes a while, the subsequent syncs are pretty fast.
## DavMail {#davmail}
is a gateway between MS Exchange and the rest of the world, which uses IMAP/SMTP/LDAP/etc. As I have one corporate MS Exchange address, this is just the program I need. As of yet, it isn't packaged for Guix, but it's easy enough to download.
It has a GUI mode, but I prefer headless config.
```ini
davmail.server=true
davmail.mode=Auto
davmail.url=https://mail.etu.ru/owa/
davmail.caldavPort=1080
davmail.imapPort=1143
davmail.ldapPort=1389
davmail.popPort=1110
davmail.smtpPort=1025
davmail.imapAutoExpunge=false
davmail.enableKeepalive=false
```
Also it's a bit of problem to get it launched as it looks for some jars in pwd, so here is a script.
```bash
cd $HOME/bin/davmail-6.0.0-3375
./davmail davmail.properties
```
Shepherd service is defined in [Desktop.org]({{< relref "Desktop" >}}).
## OfflineIMAP {#offlineimap}
| Guix dependency |
|-----------------|
| offlineimap |
[OfflineIMAP](https://github.com/OfflineIMAP/offlineimap) is a program that can synchronize IMAP mailbox and Maildir. Lieer does everything by itself, but my pirate Exchange IMAP needs this program. There is also [isync](https://isync.sourceforge.io/), but I had some weird issues with duplicate UIDs, which don't occur for OfflineIMAP.
I have a few options for setting a username and password. First, I can run `pass` in `remotepasswordeval`, and this is fine, but it will keep by keyring unlocked because I want to run `offlineimap` every couple of minutes.
Another option is to use noweb and not push the file below to the version control. Then I have a plaintext password of email on my computer, but I think it's a lesser evil than the entire keyring.
I would use `password-store-get` from password-store.el, but I want this to be able to run without any 3rd party packages, so it's just bash.
<a id="code-snippet--mail-username"></a>
```bash
pass show Job/Infrastructure/pvkorytov@etu.ru | sed -n 's/username: //;2p'
```
<a id="code-snippet--mail-password"></a>
```bash
pass show Job/Infrastructure/pvkorytov@etu.ru | head -n 1
```
```ini
[general]
accounts = pvkorytov
[Account pvkorytov]
localrepository = pvkorytov-local
remoterepository = pvkorytov-remote
[Repository pvkorytov-local]
type = Maildir
localfolders = ~/Mail/pvkorytov_etu/
[Repository pvkorytov-remote]
type = IMAP
remotehost = localhost
remoteuser = <<mail-username()>>
remotepass = <<mail-password()>>
remoteport = 1143
starttls = no
ssl = no
```
## Notmuch {#notmuch}
| Guix dependency |
|-----------------|
| notmuch |
| parallel |
Notmuch is an email indexer program, which handles labels in a way somewhat like Gmail. It also provides a frontend for Emacs, but it's not the only one available.
### Config {#config}
Not much is going on here.
First, the database path.
```ini
[database]
path=/home/pavel/Mail
```
My name and list of emails. It's not like it's a secret anyhow.
```ini
[user]
name=Pavel Korytov
primary_email=thexcloud@gmail.com
other_email=progin6304@gmail.com;pvkorytov@etu.ru
```
A list of tags which will be added by `notmuch new` and directory names which will be ignored by `notmuch new`.
```ini
[new]
tags=new;
ignore=.osync_workdir;.mbsyncstate;.uidvalidity;.lock;/.*gmailieer\.json.*/
```
Exclude these tags from search by default.
```ini
[search]
exclude_tags=trash;spam;
```
Maildir compatibility.
```ini
[maildir]
synchronize_flags=true
```
### Hooks {#hooks}
Now we have to link up lieer & Maildir and with notmuch. This is done via the notmuch hook system, which allows running custom scripts before and after any command.
With lieer and Gmail, it is enough to simply run the program, because Gmail has first-class support for tags. Maildir does not, so I decide to synchronize notmuch tags and IMAP folders. In essence, the idea is to:
- move emails to their folders by tags _before_ the synchronization
- tag mails by their folders _after_ the synchronization
The problem is that with that approach one email can have only one tag, but it's better than nothing.
So, here are the rules which match tags & folders:
<a id="table--pvkorytov-tags"></a>
| tag | folder |
|--------------------------|---------------------------|
| inbox | INBOX |
| sent | Sent |
| spam | Junk |
| trash | Trash |
| job.digital | Job\_Digital |
| job.digital.docs | Job\_Digital.Docs |
| job.digital.support | Job\_Digital.Support |
| job.digital.superservice | Job\_Digital.Superservice |
And below is a noweb function, which generates the following commands for notmuch to execute:
- _before_ sync:
- `notmuch search --output files "NOT path:[PATH] AND tag:[TAG] AND tag:[ROOT_TAG]" | xargs -I ! mv ! [PATH]`
Move emails with `TAG` but outside the matching `PATH` to the latter
- `notmuch search --output=files "NOT path:[ARCHIVE_PATH] AND tag:[ROOT_TAG] AND NOT tag:[TAG1] ... AND NOT tag:[TAGN]" | xargs -I ! mv ! [ARCHIVE_PATH]`
Move untagged emails to the `ARCHIVE_PATH`
- _after_ sync:
- `notmuch tag +[TAG] "path:[PATH] AND NOT tag:[TAG]"`
Tag emails in `PATH` which do not yet have the matching `TAG`
- `notmuch tag -[TAG] "NOT path:[PATH] AND tag:[TAG] AND tag:[ROOT_TAG]"`
Remove `TAG` from emails which are outside the matching `PATH`
These rules are getting included in the respective hooks.
<a id="code-snippet--mail-tags"></a>
```emacs-lisp
(setq my/maildir-root "~/Mail")
(let ((rules '()))
(dolist (row tags)
(let ((tag (nth 0 row))
(folder (nth 1 row)))
(unless (string-empty-p make_tag)
(add-to-list
'rules
(format "notmuch tag +%s \"path:%s/%s/cur/** AND NOT tag:%s\""
tag root folder tag)
t))
(unless (string-empty-p remove)
(add-to-list
'rules
(format "notmuch tag -%s \"NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\""
tag root folder tag root_tag)
t))
(unless (string-empty-p move)
(add-to-list
'rules
(concat
(format "notmuch search --output=files \"NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\""
root folder tag root_tag)
(format " | xargs -I ! mv ! %s/%s/%s/cur/" my/maildir-root root folder))
t))))
(unless (string-empty-p archive_root)
(add-to-list
'rules
(concat
(format "notmuch search --output=files \"NOT path:%s/%s/cur/** AND %s AND tag:%s\""
root archive_root
(mapconcat
(lambda (row)
(format "NOT tag:%s" (car row)))
tags
" AND ")
root_tag)
(format " | xargs -I ! mv ! %s/%s/%s/cur/" my/maildir-root root archive_root))
t))
(string-join rules "\n"))
```
#### `pre_new` {#pre-new}
This hook runs fetch from Gmail & offlineimap in parallel before the `notmuch new` command. The `parallel` command is provided by [GNU Parallel](https://www.gnu.org/software/parallel/).
It isn't necessary to run `cd` for offlineimap, but it's easier to write that way.
<a id="code-snippet--pre-new-pvkorytov-tags"></a>
```emacs-lisp
(my/mail-format-tags-rules tags "pvkorytov_etu" "pvkorytov" nil nil t "Archive")
```
```bash
# GMI="/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"
GMI="gmi"
echo "Running pre-new filters"
<<mail-tags(move="t",archive_root="Archive")>>
echo "Pre-new filters done"
parallel --link -j0 "(cd /home/pavel/Mail/{1}/ && {2} {3})" ::: thexcloud progin6304 pvkorytov_etu ::: "$GMI" "$GMI" "offlineimap" ::: sync sync ""
```
#### `post_new` {#post-new}
And this hook tags different mailboxes with different tags.
<a id="code-snippet--post-new-pvkorytov-tags"></a>
```emacs-lisp
(my/mail-format-tags-rules tags "pvkorytov_etu" "pvkorytov" t t)
```
```bash
notmuch tag +main "path:thexcloud/** AND tag:new"
notmuch tag +progin "path:progin6304/** AND tag:new"
notmuch tag +pvkorytov "path:pvkorytov_etu/** AND tag:new"
echo "Running post-new filters"
<<mail-tags(make_tag="t",remove="t")>>
echo "Post-new filters done"
notmuch tag -new "tag:new"
```
## Sync script {#sync-script}
A script to run `notmuch new` and push a notification if there is new mail.
```bash
export DISPLAY=:0
CHECK_FILE="/home/pavel/Mail/.last_check"
QUERY="tag:unread"
ALL_QUERY="tag:unread"
if [ -f "$CHECK_FILE" ]; then
DATE=$(cat "$CHECK_FILE")
QUERY="$QUERY and date:@$DATE.."
fi
notmuch new
NEW_UNREAD=$(notmuch count "$QUERY")
ALL_UNREAD=$(notmuch count "$ALL_QUERY")
if [ $NEW_UNREAD -gt 0 ]; then
MAIN_UNREAD=$(notmuch count "tag:unread AND tag:main")
PROGIN_UNREAD=$(notmuch count "tag:unread AND tag:progin")
ETU_UNREAD=$(notmuch count "tag:unread AND tag:pvkorytov")
read -r -d '' NOTIFICATION <<EOM
$NEW_UNREAD new messages
$MAIN_UNREAD thexcloud@gmail.com
$PROGIN_UNREAD progin6304@gmail.com
$ETU_UNREAD pvkorytov@etu.ru
$ALL_UNREAD total
EOM
notify-send "New Mail" "$NOTIFICATION"
fi
echo "$(date +%s)" > $CHECK_FILE
```
The script is ran via GNU Mcron every 5 minutes.
```scheme
(job "*/5 * * * * " "~/bin/scripts/check-email")
```
## MSMTP {#msmtp}
| Guix dependency |
|-----------------|
| msmtp |
Sending emails can be done with MSMTP. It automatially chooses the email address and server based on the contents of the message, which is handy if there are multiple mailboxes to be managed.
```vim
defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ~/.msmtp.log
account main
host smtp.gmail.com
port 587
from thexcloud@gmail.com
user thexcloud@gmail.com
passwordeval "pass show My_Online/APIs/google-main-app-password | head -n 1"
account progin
host smtp.gmail.com
port 587
from progin6304@gmail.com
user progin6304@gmail.com
passwordeval "pass show My_Online/ETU/progin6304@gmail.com | head -n 1"
account pvkorytov
tls off
auth plain
host localhost
port 1025
from pvkorytov@etu.ru
user pvkorytov
passwordeval "pass show Job/Infrastructure/pvkorytov@etu.ru | head -n 1"
```
## Emacs {#emacs}
Finally, Emacs configuration. Let's start with some variables:
```emacs-lisp
(setq user-mail-address "thexcloud@gmail.com")
(setq user-full-name "Pavel Korytov")
```
Then, the problem with my Guix setup is that Emacs by default doesn't see the elisp files of notmuch, so here is a small workaround:
```emacs-lisp
(let ((default-directory "/home/pavel/.guix-extra-profiles/mail/mail/share/emacs/site-lisp"))
(normal-top-level-add-subdirs-to-load-path))
```
Finally the proper notmuch settings:
```emacs-lisp
(use-package notmuch
;; :ensure nil
:commands (notmuch notmuch-search)
:config
(setq mail-specify-envelope-from t)
(setq message-sendmail-envelope-from 'header)
(setq mail-envelope-from 'header)
(setq notmuch-always-prompt-for-sender t)
(setq sendmail-program (executable-find "msmtp"))
(setq send-mail-function #'sendmail-send-it)
(setq mml-secure-openpgp-sign-with-sender t)
(setq notmuch-mua-user-agent-function 'notmuch-mua-user-agent-full)
(add-hook 'notmuch-hello-mode-hook
(lambda () (display-line-numbers-mode 0))))
```
The file to which this is tangled is read in the init.el.
### Saved filters and keybindings {#saved-filters-and-keybindings}
I want to have the saved filters available in both notmuch interface as as keybindings. So a bit more of abusing org tables.
Root keybindings:
```emacs-lisp
(my-leader-def
:infix "am"
"" '(:which-key "notmuch")
"m" 'notmuch)
```
<a id="table--root-tags"></a>
| Root tag | Prefix | Keybinding description |
|-----------|--------|------------------------|
| main | t | thexcloud@gmail.com |
| progin | p | progin6304@gmail.com |
| pvkorytov | e | pvkorytov@etu.ru |
<a id="table--filter-tags"></a>
| Tag | Prefix | Name |
|--------|--------|----------|
| inbox | i | inbox |
| unread | u | unread |
| sent | s | sent |
| | a | all mail |
The following formats the tables above to a proper syntax for `setq notmuch-saved-searches`:
<a id="code-snippet--format-notmuch-saved-searches"></a>
```emacs-lisp
(let ((searches '()))
(dolist (root_tag root_tags)
(dolist (tag filter_tags)
(add-to-list
'searches
(format "(:name \"%s\" :query \"%s\")"
(format "%s (%s)"
(nth 0 root_tag)
(nth 2 tag))
(concat "tag:" (nth 0 root_tag)
(unless (string-empty-p (nth 0 tag))
(concat " AND tag:" (nth 0 tag)))))
t)))
(string-join searches "\n"))
```
And the following does the same for my general.el definer:
<a id="code-snippet--format-notmuch-keybindings"></a>
```emacs-lisp
(let ((bindings '()))
(dolist (root_tag root_tags)
(add-to-list
'bindings
(format "\"%s\" '(:which-key \"%s\")"
(nth 1 root_tag)
(nth 2 root_tag))
t)
(dolist (tag filter_tags)
(add-to-list
'bindings
(format "\"%s\" '((lambda () (interactive) (notmuch-search \"%s\")) :which-key \"%s\")"
(concat (nth 1 root_tag) (nth 1 tag))
(concat "tag:" (nth 0 root_tag)
(unless (string-empty-p (nth 0 tag))
(concat " AND tag:" (nth 0 tag))))
(nth 2 tag))
t)))
(string-join bindings "\n"))
```
```emacs-lisp
(setq notmuch-saved-searches
'((:name "drafts" :query "tag:draft")
<<format-notmuch-saved-searches()>>))
(my-leader-def
:infix "am"
<<format-notmuch-keybindings()>>)
```
### Signing messages {#signing-messages}
```emacs-lisp
(with-eval-after-load 'notmuch
(add-hook 'message-setup-hook 'mml-secure-sign-pgpmime))
(setq mml-secure-key-preferences
'((OpenPGP
(sign
("thexcloud@gmail.com" "914472A1FD6775C166F96EBEED739ADF81C78160"))
(encrypt))
(CMS
(sign)
(encrypt))))
```
## mailcap {#mailcap}
mailcap file is a file which defines how to read to different MIME types. Notmuch also uses it, so why not keep it here.
```text
audio/*; mpc add %s
image/*; feh %s
application/msword; /usr/bin/xdg-open %s
application/pdf; zathura %s
application/postscript ; zathura %s
text/html; firefox %s
```
## Guix settings {#guix-settings}
<a id="code-snippet--packages"></a>
```emacs-lisp
(my/format-guix-dependencies)
```
```scheme
(specifications->manifest
'(
<<packages()>>))
```

114
content/configs/README.md Normal file
View file

@ -0,0 +1,114 @@
+++
title = "My dotfiles"
author = ["Pavel"]
aliases = ["/config"]
draft = false
+++
{{< figure src="https://forthebadge.com/images/badges/works-on-my-machine.svg" >}}
A set of my GNU/Linux configuration files. [View at GitHub](https://github.com/SqrtMinusOne/dotfiles).
The majority of the software is configured with [literate configuration](https://leanpub.com/lit-config/read) strategy via Emacs' Org Mode. This way has its advantages and disadvantages, but overall it's pretty nice to keep the configs interweaved with comments in a handful of files.
The files themselves are managed and deployed via [yadm](https://yadm.io/), but I mostly use Org Mode rich noweb whenever I can instead of what yadm offers.
My current GNU/Linux distribution is [GNU Guix](https://guix.gnu.org/). In the context of this repo, Guix allows me to list all the used programs in manifests, which means I have the same set of programs across multiple machines. Looks for Org tables with "Guix dependency" in the header.
Literate configuration files:
- [Emacs.org]({{< relref "Emacs" >}})
- [Desktop.org]({{< relref "Desktop" >}})
- [Console.org]({{< relref "Console" >}})
- [Guix.org]({{< relref "Guix" >}})
- [Mail.org]({{< relref "Mail" >}})
## Programs used {#programs-used}
Some of the notable programs are listed in the table below.
| Group | Program | Purpose | Status | Documented? | Notes |
|-----------|---------------------------------------------------------|-----------------------------|------------------|---------------------------------------------------------------------------------------------|-----------------------------------------------------------|
| console | bash | shell | launches fish :) | [Console.org]({{< relref "Console" >}}) | |
| console | [fish](https://fishshell.com/) | shell | **active** | [Console.org]({{< relref "Console" >}}) | |
| console | [starship](https://github.com/starship/starship) | prompt | **active** | [Console.org]({{< relref "Console" >}}) | |
| console | [tmux](https://github.com/tmux/tmux) | terminal multiplexer | **active** | [Console.org]({{< relref "Console" >}}) | |
| console | [alacritty](https://github.com/alacritty/alacritty) | terminal emulator | **active** | [Console.org]({{< relref "Console" >}}) | |
| mail | [notmuch](https://notmuchmail.org/) | mail indexer | **active** | [Mail.org,]({{< relref "Mail" >}}) [post](https://sqrtminusone.xyz/posts/2021-02-27-gmail/) | |
| mail | [lieer](https://github.com/gauteh/lieer) | gmail API client | **active** | [Mail.org]({{< relref "Mail" >}}), [post](https://sqrtminusone.xyz/posts/2021-02-27-gmail/) | credentials are encrypted |
| mail | [msmtp](https://marlam.de/msmtp/) | SMTP client | **active** | [Mail.org]({{< relref "Mail" >}}) | |
| editor | [emacs](https://www.gnu.org/software/emacs/) | everything | **active** | [Emacs.org]({{< relref "Emacs" >}}) | GitHub renders .org files without labels and `tangle: no` |
| editor | [vim](https://www.vim.org/) | text edtior | **active** | - | A minimal config to have a lightweight terminal $EDITOR |
| editor | [neovim](https://neovim.io/) | text edtior | archive | - | |
| documents | [latexmk](https://mg.readthedocs.io/latexmk.html) | LaTeX build tool | **active** | - | |
| documents | [zathura](https://pwmt.org/projects/zathura/) | pdf viewer | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [dunst](https://github.com/dunst-project/dunst) | notification manager | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [i3wm](https://i3wm.org/) | tiling WM | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [keynav](https://github.com/jordansissel/keynav) | control mouse with keyboard | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [polybar](https://github.com/polybar/polybar) | status bar | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [rofi](https://github.com/davatorium/rofi) | generic menu | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [flameshot](https://github.com/flameshot-org/flameshot) | screenshot | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [picom](https://github.com/yshui/picom) | X11 compositor | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [i3blocks](https://github.com/vivien/i3blocks) | status bar | archive | - | |
| internet | [tridactyl](https://github.com/tridactyl/tridactyl) | vim bindings for Firefox | **active** | - | templated with yadm |
| internet | [newsboat](https://newsboat.org/) | terminal RSS reader | archive | - | urls are encrypted |
| internet | [qutebrowser](https://qutebrowser.org/) | browser with vim bindings | archive | - | |
| internet | [buku](https://github.com/jarun/buku) | bookmarks manager | archive | - | |
| audio | [mpd](https://www.musicpd.org/) | music player daemon | **active** | - | |
| audio | [ncmpcpp](https://github.com/ncmpcpp/ncmpcpp) | MPD frontend | **active** | - | |
| misc | [yadm](https://yadm.io) | dotfiles manager | **active** | - | |
| misc | [sunwait](https://github.com/risacher/sunwait) | sunrise calculator | **active** | - | |
| misc | [vnstat](https://github.com/vergoh/vnstat) | traffic stats | **active** | - | |
## Posts about my configuration {#posts-about-my-configuration}
- [Replacing Jupyter Notebook with Org Mode](https://sqrtminusone.xyz/posts/2021-05-01-org-python/)
- [Multiple Gmail accounts & labels with Emacs](https://sqrtminusone.xyz/posts/2021-02-27-gmail/)
## Some statistics {#some-statistics}
Run the following to show the pictures with reasonable width:
```elisp
(setq-local org-image-actual-width '(1024))
```
### History {#history}
{{< figure src="/ox-hugo/all.png" >}}
{{< figure src="/ox-hugo/emacs-vim.png" >}}
{{< figure src="/ox-hugo/literate-config.png" >}}
## Misc {#misc}
### Notes {#notes}
- `M-u C-c C-v t` to tangle a particular block
- `M-u M-u C-c C-v t` to tangle a particular file
- `C-c C-v d` to demarcate a block
Uses yadm's `post_alt` hook to create symlinks
### Encrypted files {#encrypted-files}
```text
.config/newsboat/urls
.config/filezilla/sitemanager.xml
.config/filezilla/filezilla.xml
Mail/thexcloud/.credentials.gmailieer.json
Mail/progin6304/.credentials.gmailieer.json
.emacs.d/dired-bookmarks.el
.emacs.d/elfeed.org
.emacs.d/private.org
.emacs.d/prodigy-config.el
.emacs.d/private.el
```

114
content/configs/README.md~ Normal file
View file

@ -0,0 +1,114 @@
+++
title = "My dotfiles"
author = ["Pavel"]
aliases = ["/configs/config"]
draft = false
+++
{{< figure src="https://forthebadge.com/images/badges/works-on-my-machine.svg" >}}
A set of my GNU/Linux configuration files. [View at GitHub](https://github.com/SqrtMinusOne/dotfiles).
The majority of the software is configured with [literate configuration](https://leanpub.com/lit-config/read) strategy via Emacs' Org Mode. This way has its advantages and disadvantages, but overall it's pretty nice to keep the configs interweaved with comments in a handful of files.
The files themselves are managed and deployed via [yadm](https://yadm.io/), but I mostly use Org Mode rich noweb whenever I can instead of what yadm offers.
My current GNU/Linux distribution is [GNU Guix](https://guix.gnu.org/). In the context of this repo, Guix allows me to list all the used programs in manifests, which means I have the same set of programs across multiple machines. Looks for Org tables with "Guix dependency" in the header.
Literate configuration files:
- [Emacs.org]({{< relref "Emacs" >}})
- [Desktop.org]({{< relref "Desktop" >}})
- [Console.org]({{< relref "Console" >}})
- [Guix.org]({{< relref "Guix" >}})
- [Mail.org]({{< relref "Mail" >}})
## Programs used {#programs-used}
Some of the notable programs are listed in the table below.
| Group | Program | Purpose | Status | Documented? | Notes |
|-----------|---------------------------------------------------------|-----------------------------|------------------|---------------------------------------------------------------------------------------------|-----------------------------------------------------------|
| console | bash | shell | launches fish :) | [Console.org]({{< relref "Console" >}}) | |
| console | [fish](https://fishshell.com/) | shell | **active** | [Console.org]({{< relref "Console" >}}) | |
| console | [starship](https://github.com/starship/starship) | prompt | **active** | [Console.org]({{< relref "Console" >}}) | |
| console | [tmux](https://github.com/tmux/tmux) | terminal multiplexer | **active** | [Console.org]({{< relref "Console" >}}) | |
| console | [alacritty](https://github.com/alacritty/alacritty) | terminal emulator | **active** | [Console.org]({{< relref "Console" >}}) | |
| mail | [notmuch](https://notmuchmail.org/) | mail indexer | **active** | [Mail.org,]({{< relref "Mail" >}}) [post](https://sqrtminusone.xyz/posts/2021-02-27-gmail/) | |
| mail | [lieer](https://github.com/gauteh/lieer) | gmail API client | **active** | [Mail.org]({{< relref "Mail" >}}), [post](https://sqrtminusone.xyz/posts/2021-02-27-gmail/) | credentials are encrypted |
| mail | [msmtp](https://marlam.de/msmtp/) | SMTP client | **active** | [Mail.org]({{< relref "Mail" >}}) | |
| editor | [emacs](https://www.gnu.org/software/emacs/) | everything | **active** | [Emacs.org]({{< relref "Emacs" >}}) | GitHub renders .org files without labels and `tangle: no` |
| editor | [vim](https://www.vim.org/) | text edtior | **active** | - | A minimal config to have a lightweight terminal $EDITOR |
| editor | [neovim](https://neovim.io/) | text edtior | archive | - | |
| documents | [latexmk](https://mg.readthedocs.io/latexmk.html) | LaTeX build tool | **active** | - | |
| documents | [zathura](https://pwmt.org/projects/zathura/) | pdf viewer | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [dunst](https://github.com/dunst-project/dunst) | notification manager | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [i3wm](https://i3wm.org/) | tiling WM | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [keynav](https://github.com/jordansissel/keynav) | control mouse with keyboard | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [polybar](https://github.com/polybar/polybar) | status bar | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [rofi](https://github.com/davatorium/rofi) | generic menu | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [flameshot](https://github.com/flameshot-org/flameshot) | screenshot | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [picom](https://github.com/yshui/picom) | X11 compositor | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [i3blocks](https://github.com/vivien/i3blocks) | status bar | archive | - | |
| internet | [tridactyl](https://github.com/tridactyl/tridactyl) | vim bindings for Firefox | **active** | - | templated with yadm |
| internet | [newsboat](https://newsboat.org/) | terminal RSS reader | archive | - | urls are encrypted |
| internet | [qutebrowser](https://qutebrowser.org/) | browser with vim bindings | archive | - | |
| internet | [buku](https://github.com/jarun/buku) | bookmarks manager | archive | - | |
| audio | [mpd](https://www.musicpd.org/) | music player daemon | **active** | - | |
| audio | [ncmpcpp](https://github.com/ncmpcpp/ncmpcpp) | MPD frontend | **active** | - | |
| misc | [yadm](https://yadm.io) | dotfiles manager | **active** | - | |
| misc | [sunwait](https://github.com/risacher/sunwait) | sunrise calculator | **active** | - | |
| misc | [vnstat](https://github.com/vergoh/vnstat) | traffic stats | **active** | - | |
## Posts about my configuration {#posts-about-my-configuration}
- [Replacing Jupyter Notebook with Org Mode](https://sqrtminusone.xyz/posts/2021-05-01-org-python/)
- [Multiple Gmail accounts & labels with Emacs](https://sqrtminusone.xyz/posts/2021-02-27-gmail/)
## Some statistics {#some-statistics}
Run the following to show the pictures with reasonable width:
```elisp
(setq-local org-image-actual-width '(1024))
```
### History {#history}
{{< figure src="/ox-hugo/all.png" >}}
{{< figure src="/ox-hugo/emacs-vim.png" >}}
{{< figure src="/ox-hugo/literate-config.png" >}}
## Misc {#misc}
### Notes {#notes}
- `M-u C-c C-v t` to tangle a particular block
- `M-u M-u C-c C-v t` to tangle a particular file
- `C-c C-v d` to demarcate a block
Uses yadm's `post_alt` hook to create symlinks
### Encrypted files {#encrypted-files}
```text
.config/newsboat/urls
.config/filezilla/sitemanager.xml
.config/filezilla/filezilla.xml
Mail/thexcloud/.credentials.gmailieer.json
Mail/progin6304/.credentials.gmailieer.json
.emacs.d/dired-bookmarks.el
.emacs.d/elfeed.org
.emacs.d/private.org
.emacs.d/prodigy-config.el
.emacs.d/private.el
```

113
content/configs/index.md~ Normal file
View file

@ -0,0 +1,113 @@
+++
title = "My dotfiles"
author = ["Pavel"]
draft = false
+++
{{< figure src="https://forthebadge.com/images/badges/works-on-my-machine.svg" >}}
A set of my GNU/Linux configuration files. [View at GitHub](https://github.com/SqrtMinusOne/dotfiles).
The majority of the software is configured with [literate configuration](https://leanpub.com/lit-config/read) strategy via Emacs' Org Mode. This way has its advantages and disadvantages, but overall it's pretty nice to keep the configs interweaved with comments in a handful of files.
The files themselves are managed and deployed via [yadm](https://yadm.io/), but I mostly use Org Mode rich noweb whenever I can instead of what yadm offers.
My current GNU/Linux distribution is [GNU Guix](https://guix.gnu.org/). In the context of this repo, Guix allows me to list all the used programs in manifests, which means I have the same set of programs across multiple machines. Looks for Org tables with "Guix dependency" in the header.
Literate configuration files:
- [Emacs.org]({{< relref "Emacs" >}})
- [Desktop.org]({{< relref "Desktop" >}})
- [Console.org]({{< relref "Console" >}})
- [Guix.org]({{< relref "Guix" >}})
- [Mail.org]({{< relref "Mail" >}})
## Programs used {#programs-used}
Some of the notable programs are listed in the table below.
| Group | Program | Purpose | Status | Documented? | Notes |
|-----------|---------------------------------------------------------|-----------------------------|------------------|---------------------------------------------------------------------------------------------|-----------------------------------------------------------|
| console | bash | shell | launches fish :) | [Console.org]({{< relref "Console" >}}) | |
| console | [fish](https://fishshell.com/) | shell | **active** | [Console.org]({{< relref "Console" >}}) | |
| console | [starship](https://github.com/starship/starship) | prompt | **active** | [Console.org]({{< relref "Console" >}}) | |
| console | [tmux](https://github.com/tmux/tmux) | terminal multiplexer | **active** | [Console.org]({{< relref "Console" >}}) | |
| console | [alacritty](https://github.com/alacritty/alacritty) | terminal emulator | **active** | [Console.org]({{< relref "Console" >}}) | |
| mail | [notmuch](https://notmuchmail.org/) | mail indexer | **active** | [Mail.org,]({{< relref "Mail" >}}) [post](https://sqrtminusone.xyz/posts/2021-02-27-gmail/) | |
| mail | [lieer](https://github.com/gauteh/lieer) | gmail API client | **active** | [Mail.org]({{< relref "Mail" >}}), [post](https://sqrtminusone.xyz/posts/2021-02-27-gmail/) | credentials are encrypted |
| mail | [msmtp](https://marlam.de/msmtp/) | SMTP client | **active** | [Mail.org]({{< relref "Mail" >}}) | |
| editor | [emacs](https://www.gnu.org/software/emacs/) | everything | **active** | [Emacs.org]({{< relref "Emacs" >}}) | GitHub renders .org files without labels and `tangle: no` |
| editor | [vim](https://www.vim.org/) | text edtior | **active** | - | A minimal config to have a lightweight terminal $EDITOR |
| editor | [neovim](https://neovim.io/) | text edtior | archive | - | |
| documents | [latexmk](https://mg.readthedocs.io/latexmk.html) | LaTeX build tool | **active** | - | |
| documents | [zathura](https://pwmt.org/projects/zathura/) | pdf viewer | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [dunst](https://github.com/dunst-project/dunst) | notification manager | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [i3wm](https://i3wm.org/) | tiling WM | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [keynav](https://github.com/jordansissel/keynav) | control mouse with keyboard | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [polybar](https://github.com/polybar/polybar) | status bar | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [rofi](https://github.com/davatorium/rofi) | generic menu | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [flameshot](https://github.com/flameshot-org/flameshot) | screenshot | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [picom](https://github.com/yshui/picom) | X11 compositor | **active** | [Desktop.org]({{< relref "Desktop" >}}) | |
| desktop | [i3blocks](https://github.com/vivien/i3blocks) | status bar | archive | - | |
| internet | [tridactyl](https://github.com/tridactyl/tridactyl) | vim bindings for Firefox | **active** | - | templated with yadm |
| internet | [newsboat](https://newsboat.org/) | terminal RSS reader | archive | - | urls are encrypted |
| internet | [qutebrowser](https://qutebrowser.org/) | browser with vim bindings | archive | - | |
| internet | [buku](https://github.com/jarun/buku) | bookmarks manager | archive | - | |
| audio | [mpd](https://www.musicpd.org/) | music player daemon | **active** | - | |
| audio | [ncmpcpp](https://github.com/ncmpcpp/ncmpcpp) | MPD frontend | **active** | - | |
| misc | [yadm](https://yadm.io) | dotfiles manager | **active** | - | |
| misc | [sunwait](https://github.com/risacher/sunwait) | sunrise calculator | **active** | - | |
| misc | [vnstat](https://github.com/vergoh/vnstat) | traffic stats | **active** | - | |
## Posts about my configuration {#posts-about-my-configuration}
- [Replacing Jupyter Notebook with Org Mode](https://sqrtminusone.xyz/posts/2021-05-01-org-python/)
- [Multiple Gmail accounts & labels with Emacs](https://sqrtminusone.xyz/posts/2021-02-27-gmail/)
## Some statistics {#some-statistics}
Run the following to show the pictures with reasonable width:
```elisp
(setq-local org-image-actual-width '(1024))
```
### History {#history}
{{< figure src="/ox-hugo/all.png" >}}
{{< figure src="/ox-hugo/emacs-vim.png" >}}
{{< figure src="/ox-hugo/literate-config.png" >}}
## Misc {#misc}
### Notes {#notes}
- `M-u C-c C-v t` to tangle a particular block
- `M-u M-u C-c C-v t` to tangle a particular file
- `C-c C-v d` to demarcate a block
Uses yadm's `post_alt` hook to create symlinks
### Encrypted files {#encrypted-files}
```text
.config/newsboat/urls
.config/filezilla/sitemanager.xml
.config/filezilla/filezilla.xml
Mail/thexcloud/.credentials.gmailieer.json
Mail/progin6304/.credentials.gmailieer.json
.emacs.d/dired-bookmarks.el
.emacs.d/elfeed.org
.emacs.d/private.org
.emacs.d/prodigy-config.el
.emacs.d/private.el
```

View file

@ -30,6 +30,8 @@
(setq org-hugo-section "configs")
(setq org-hugo-base-dir "../../")
;; (setq org-hugo-export-with-toc 6)
(setq my/config-files '("README.org"
"Emacs.org"
"Desktop.org"
@ -47,8 +49,13 @@
(org-mode)
(insert-file-contents file)
(unless (string-equal file "README.org")
(setq org-make-toc-link-type-fn #'org-make-toc--link-entry-org)
(org-make-toc))
(replace-string "conf-space" "vim" t (point-min) (point-max))
(replace-string "conf-unix" "ini" t (point-min) (point-max))
(replace-string "conf-windows" "ini" t (point-min) (point-max))
(replace-string "conf-xdefaults" "vim" t (point-min) (point-max))
(replace-string "conf-toml" "toml" t (point-min) (point-max))
(replace-string ":noweb yes" ":noweb no-export" nil (point-min) (point-max))
(setq-local buffer-file-name file)
(message "Publish %s" file)
(org-hugo-export-to-md)))

View file

@ -11,7 +11,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
@ -43,6 +43,13 @@
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>

View file

@ -11,7 +11,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
@ -44,6 +44,13 @@
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>

View file

@ -0,0 +1,961 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Console</title>
<meta name="description" content="Freedom is a state of mind">
<meta name="author" content='SqrtMinusOne'>
<link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
</head>
<body><div class="container mt-5">
<nav class="navbar navbar-expand-sm flex-column flex-sm-row text-nowrap p-0">
<a class="navbar-brand mx-0 mr-sm-auto" href="https://sqrtminusone.xyz/">
SqrtMinusOne
</a>
<div class="navbar-nav flex-row flex-wrap justify-content-center">
<a class="nav-item nav-link" href="/">
Index
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/posts/">
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>
</nav>
</div>
<hr>
<div id="content">
<div class="container">
<p>#+TOC headlines 6</p>
<h2 id="dot-profile"><code>.profile</code></h2>
<h3 id="environment">Environment</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#75715e"># export EDITOR=/usr/bin/vim</span>
<span style="color:#75715e"># export BROWSER=/usr/bin/firefox</span>
export QT_QPA_PLATFORMTHEME<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;qt5ct&#34;</span>
export QT_AUTO_SCREEN_SCALE_FACTOR<span style="color:#f92672">=</span><span style="color:#ae81ff">0</span>
<span style="color:#75715e"># export GTK2_RC_FILES=&#34;$HOME/.gtkrc-2.0&#34;</span>
</code></pre></div><h3 id="my-paths">My paths</h3>
<p>My script folders</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -d <span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/bin&#34;</span> <span style="color:#f92672">]</span> ; <span style="color:#66d9ef">then</span>
export PATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/bin:</span>$PATH<span style="color:#e6db74">&#34;</span>
export PATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/bin/scripts:</span>$PATH<span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><h3 id="guix-settings">Guix settings</h3>
<p>Enable extra profiles</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">&#34;</span>$IS_ANDROID<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
GUIX_EXTRA_PROFILES<span style="color:#f92672">=</span>$HOME/.guix-extra-profiles
<span style="color:#66d9ef">for</span> i in $GUIX_EXTRA_PROFILES/*; <span style="color:#66d9ef">do</span>
profile<span style="color:#f92672">=</span>$i/<span style="color:#66d9ef">$(</span>basename <span style="color:#e6db74">&#34;</span>$i<span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">)</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -f <span style="color:#e6db74">&#34;</span>$profile<span style="color:#e6db74">&#34;</span>/etc/profile <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
GUIX_PROFILE<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$profile<span style="color:#e6db74">&#34;</span>
. <span style="color:#e6db74">&#34;</span>$GUIX_PROFILE<span style="color:#e6db74">&#34;</span>/etc/profile
<span style="color:#66d9ef">fi</span>
export XDG_DATA_DIRS<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$XDG_DATA_DIRS<span style="color:#e6db74">:</span>$profile<span style="color:#e6db74">/share&#34;</span>
unset profile
<span style="color:#66d9ef">done</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><p>Set Jupyter config PATH. It defaults to readonly directory somewhere in Guix profile.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">export JUPYTER_CONFIG_DIR<span style="color:#f92672">=</span>$HOME/.config/jupyter
</code></pre></div><p>Set a folder for my packages.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">export GUIX_PACKAGE_PATH<span style="color:#f92672">=</span>~/guix-packages
</code></pre></div><h3 id="other-package-managers">Other package managers</h3>
<p>Using other package managers with Guix requires some extra work.</p>
<p>Cask</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -d <span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/.cask&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
export PATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/home/pavel/.cask/bin:</span>$PATH<span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><p>Make flatpak apps visible to launchers:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -d <span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/.local/share/flatpak&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
export XDG_DATA_DIRS<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$XDG_DATA_DIRS<span style="color:#e6db74">:</span>$HOME<span style="color:#e6db74">/.local/share/flatpak/exports/share&#34;</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><p>Enable Nix</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -f /run/current-system/profile/etc/profile.d/nix.sh <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
. /run/current-system/profile/etc/profile.d/nix.sh
<span style="color:#66d9ef">fi</span>
</code></pre></div><p>Use Guix fontconfig. Necessary for nix apps</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -d <span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/.guix-extra-profiles/desktop&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
export FONTCONFIG_PATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/.guix-extra-profiles/desktop/desktop/etc/fonts&#34;</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><p>Make nix apps visible to launchers:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -d <span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/.nix-profile&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
export XDG_DATA_DIRS<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$XDG_DATA_DIRS<span style="color:#e6db74">:</span>$HOME<span style="color:#e6db74">/.nix-profile/share/applications&#34;</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><h4 id="npm">npm</h4>
<p>npm is especially cumbersome, for instance because by default it tries to install packages to <code>/gnu/store/</code>.</p>
<p>In principle, one can set a prefix like this:</p>
<pre><code class="language-conf" data-lang="conf">prefix=/home/pavel/.npm-packages
</code></pre><p>But I also want to use node from conda occasionally, where prefix is already set correctly. So instead of tangling the above to the <code>~/.npmrc</code> directly, I set an environment variable in the profile:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">export NPM_CONFIG_USERCONFIG<span style="color:#f92672">=</span>$HOME/._npmrc
</code></pre></div><p>The variable is unset in a script in <a href="/configs/guix/">Guix.org</a>.</p>
<p>Set PATH &amp; MANPATH</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">NPM_PACKAGES<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>HOME<span style="color:#e6db74">}</span><span style="color:#e6db74">/.npm-packages&#34;</span>
export PATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$PATH<span style="color:#e6db74">:</span>$NPM_PACKAGES<span style="color:#e6db74">/bin&#34;</span>
export MANPATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>MANPATH-<span style="color:#66d9ef">$(</span>manpath<span style="color:#66d9ef">)</span><span style="color:#e6db74">}</span><span style="color:#e6db74">:</span>$NPM_PACKAGES<span style="color:#e6db74">/share/man&#34;</span>
</code></pre></div><h3 id="xresources">XResources</h3>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>xrdb</td>
</tr>
</tbody>
</table>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">&#34;</span>$IS_ANDROID<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
xrdb ~/.Xresources
<span style="color:#66d9ef">fi</span>
</code></pre></div><h3 id="off--package-manager-paths"><span class="org-todo done OFF">OFF</span> (OFF) Package manager paths</h3>
<p>Turned off for now, because probably it won&rsquo;t be necessary in Guix.</p>
<p>LaTeX</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -d <span style="color:#e6db74">&#34;/usr/local/texlive/2020&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
export MANPATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/usr/local/texlive/2020/texmf-dist/doc/man:</span>$MANPATH<span style="color:#e6db74">&#34;</span>
export INFOPATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/usr/local/texlive/2020/texmf-dist/doc/info:</span>$INFOPATH<span style="color:#e6db74">&#34;</span>
export PATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/usr/local/texlive/2020/bin/x86_64-linux:</span>$PATH<span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><p>Cargo (Rust)</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -d <span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/.cargo&#34;</span> <span style="color:#f92672">]</span> ; <span style="color:#66d9ef">then</span>
export PATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/.cargo/bin:</span>$PATH<span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><p>RVM (Ruby)</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -d <span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/.rvm&#34;</span> <span style="color:#f92672">]</span> ; <span style="color:#66d9ef">then</span>
export PATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$PATH<span style="color:#e6db74">:</span>$HOME<span style="color:#e6db74">/.rvm/bin&#34;</span>
<span style="color:#66d9ef">fi</span>
<span style="color:#75715e"># if [ -d &#34;$HOME/.gem&#34; ]; then</span>
<span style="color:#75715e"># export PATH=&#34;$HOME/.gem/ruby/2.7.0/bin:$PATH&#34;</span>
<span style="color:#75715e"># fi</span>
</code></pre></div><p>Go</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -d <span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/go&#34;</span> <span style="color:#f92672">]</span> ; <span style="color:#66d9ef">then</span>
export PATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/go/bin:</span>$PATH<span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><p>ghcup (Haskell)</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#f92672">[</span> -f <span style="color:#e6db74">&#34;/home/pavel/.ghcup/env&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> source <span style="color:#e6db74">&#34;/home/pavel/.ghcup/env&#34;</span> <span style="color:#75715e"># ghcup-env</span>
</code></pre></div><p>Perl</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -d <span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/perl5&#34;</span> <span style="color:#f92672">]</span> ; <span style="color:#66d9ef">then</span>
PATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/home/pavel/perl5/bin</span><span style="color:#e6db74">${</span>PATH:+:<span style="color:#e6db74">${</span>PATH<span style="color:#e6db74">}}</span><span style="color:#e6db74">&#34;</span>
PERL5LIB<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/home/pavel/perl5/lib/perl5</span><span style="color:#e6db74">${</span>PERL5LIB:+:<span style="color:#e6db74">${</span>PERL5LIB<span style="color:#e6db74">}}</span><span style="color:#e6db74">&#34;</span>; export PERL5LIB;
PERL_LOCAL_LIB_ROOT<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/home/pavel/perl5</span><span style="color:#e6db74">${</span>PERL_LOCAL_LIB_ROOT:+:<span style="color:#e6db74">${</span>PERL_LOCAL_LIB_ROOT<span style="color:#e6db74">}}</span><span style="color:#e6db74">&#34;</span>; export PERL_LOCAL_LIB_ROOT;
PERL_MB_OPT<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;--install_base \&#34;/home/pavel/perl5\&#34;&#34;</span>; export PERL_MB_OPT;
PERL_MM_OPT<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;INSTALL_BASE=/home/pavel/perl5&#34;</span>; export PERL_MM_OPT;
<span style="color:#66d9ef">fi</span>
</code></pre></div><h2 id="bash">Bash</h2>
<h3 id="dot-bash-profile"><code>.bash_profile</code></h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#f92672">[[</span> -f ~/.profile <span style="color:#f92672">]]</span> <span style="color:#f92672">&amp;&amp;</span> . ~/.profile
<span style="color:#f92672">[[</span> -f ~/.bashrc <span style="color:#f92672">]]</span> <span style="color:#f92672">&amp;&amp;</span> . ~/.bashrc
</code></pre></div><h3 id="dot-bashrc"><code>.bashrc</code></h3>
<p>My <code>.bashrc</code>, which has pieces from the default ones in Guix &amp; Manjaro, as well some mine settings.</p>
<h4 id="startup-and-environment">Startup &amp; environment</h4>
<p>Export &lsquo;SHELL&rsquo; to child processes. Programs such as &lsquo;screen&rsquo; honor it and otherwise use /bin/sh.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">export SHELL
</code></pre></div><p>We are being invoked from a non-interactive shell. If this is an SSH session (as in &ldquo;ssh host command&rdquo;), source /etc/profile so we get PATH and other essential variables.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> $- !<span style="color:#f92672">=</span> *i* <span style="color:#f92672">]]</span>
<span style="color:#66d9ef">then</span>
<span style="color:#f92672">[[</span> -n <span style="color:#e6db74">&#34;</span>$SSH_CLIENT<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">&amp;&amp;</span> -f <span style="color:#e6db74">&#34;/etc/bashrc&#34;</span> <span style="color:#f92672">]]</span> <span style="color:#f92672">&amp;&amp;</span> source /etc/profile
<span style="color:#66d9ef">return</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><p>Source the system-wide file</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> -f <span style="color:#e6db74">&#34;/etc/bashrc&#34;</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
source /etc/bashrc
<span style="color:#66d9ef">fi</span>
</code></pre></div><table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>xhost</td>
</tr>
</tbody>
</table>
<p>Allow other users to access X server. Necessary for stuff like aw-watcher-window.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">xhost +local:root &gt; /dev/null 2&gt;&amp;<span style="color:#ae81ff">1</span>
</code></pre></div><p>Set manpager to bat</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">export MANPAGER<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sh -c &#39;sed -e s/.\\\\x08//g | bat -l man -p&#39;&#34;</span>
</code></pre></div><h4 id="launch-fish">Launch fish</h4>
<p>Launch fish shell unless bash itself is launched from fish.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">use_fish<span style="color:#f92672">=</span>true
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> <span style="color:#66d9ef">$(</span>ps --no-header --pid<span style="color:#f92672">=</span>$PPID --format<span style="color:#f92672">=</span>cmd<span style="color:#66d9ef">)</span> !<span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;fish&#34;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#e6db74">${</span>use_fish<span style="color:#e6db74">}</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#66d9ef">$(</span>command -v fish<span style="color:#66d9ef">)</span> <span style="color:#f92672">]]</span>
<span style="color:#66d9ef">then</span>
exec fish
<span style="color:#66d9ef">fi</span>
</code></pre></div><p>The rest of <code>.bashrc</code> is not executed if fish was launched.</p>
<h4 id="colors">Colors</h4>
<p>Setting for colors, packed in the default <code>.bashrc</code> in Manjaro</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">use_color<span style="color:#f92672">=</span>true
<span style="color:#75715e"># Set colorful PS1 only on colorful terminals.</span>
<span style="color:#75715e"># dircolors --print-database uses its own built-in database</span>
<span style="color:#75715e"># instead of using /etc/DIR_COLORS. Try to use the external file</span>
<span style="color:#75715e"># first to take advantage of user additions. Use internal bash</span>
<span style="color:#75715e"># globbing instead of external grep binary.</span>
safe_term<span style="color:#f92672">=</span><span style="color:#e6db74">${</span>TERM//[^[:alnum:]]/?<span style="color:#e6db74">}</span> <span style="color:#75715e"># sanitize TERM</span>
match_lhs<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;&#34;</span>
<span style="color:#f92672">[[</span> -f ~/.dir_colors <span style="color:#f92672">]]</span> <span style="color:#f92672">&amp;&amp;</span> match_lhs<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>match_lhs<span style="color:#e6db74">}</span><span style="color:#66d9ef">$(</span>&lt;~/.dir_colors<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>
<span style="color:#f92672">[[</span> -f /etc/DIR_COLORS <span style="color:#f92672">]]</span> <span style="color:#f92672">&amp;&amp;</span> match_lhs<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>match_lhs<span style="color:#e6db74">}</span><span style="color:#66d9ef">$(</span>&lt;/etc/DIR_COLORS<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>
<span style="color:#f92672">[[</span> -z <span style="color:#e6db74">${</span>match_lhs<span style="color:#e6db74">}</span> <span style="color:#f92672">]]</span> <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> <span style="color:#f92672">&amp;&amp;</span> type -P dircolors &gt;/dev/null <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> <span style="color:#f92672">&amp;&amp;</span> match_lhs<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>dircolors --print-database<span style="color:#66d9ef">)</span>
<span style="color:#f92672">[[</span> <span style="color:#e6db74">$&#39;\n&#39;</span><span style="color:#e6db74">${</span>match_lhs<span style="color:#e6db74">}</span> <span style="color:#f92672">==</span> *<span style="color:#e6db74">$&#39;\n&#39;</span><span style="color:#e6db74">&#34;TERM &#34;</span><span style="color:#e6db74">${</span>safe_term<span style="color:#e6db74">}</span>* <span style="color:#f92672">]]</span> <span style="color:#f92672">&amp;&amp;</span> use_color<span style="color:#f92672">=</span>true
<span style="color:#66d9ef">if</span> <span style="color:#e6db74">${</span>use_color<span style="color:#e6db74">}</span> ; <span style="color:#66d9ef">then</span>
<span style="color:#75715e"># Enable colors for ls, etc. Prefer ~/.dir_colors #64489</span>
<span style="color:#66d9ef">if</span> type -P dircolors &gt;/dev/null ; <span style="color:#66d9ef">then</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> -f ~/.dir_colors <span style="color:#f92672">]]</span> ; <span style="color:#66d9ef">then</span>
eval <span style="color:#66d9ef">$(</span>dircolors -b ~/.dir_colors<span style="color:#66d9ef">)</span>
<span style="color:#66d9ef">elif</span> <span style="color:#f92672">[[</span> -f /etc/DIR_COLORS <span style="color:#f92672">]]</span> ; <span style="color:#66d9ef">then</span>
eval <span style="color:#66d9ef">$(</span>dircolors -b /etc/DIR_COLORS<span style="color:#66d9ef">)</span>
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> <span style="color:#e6db74">${</span>EUID<span style="color:#e6db74">}</span> <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> <span style="color:#f92672">]]</span> ; <span style="color:#66d9ef">then</span>
PS1<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;\[\033[01;31m\][\h\[\033[01;36m\] \W\[\033[01;31m\]]\$\[\033[00m\] &#39;</span>
<span style="color:#66d9ef">else</span>
PS1<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;\[\033[01;32m\][\u@\h\[\033[01;37m\] \W\[\033[01;32m\]]\$\[\033[00m\] &#39;</span>
<span style="color:#66d9ef">fi</span>
alias ls<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;ls --color=auto&#39;</span>
alias grep<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;grep --colour=auto&#39;</span>
alias egrep<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;egrep --colour=auto&#39;</span>
alias fgrep<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;fgrep --colour=auto&#39;</span>
<span style="color:#66d9ef">else</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> <span style="color:#e6db74">${</span>EUID<span style="color:#e6db74">}</span> <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> <span style="color:#f92672">]]</span> ; <span style="color:#66d9ef">then</span>
<span style="color:#75715e"># show root@ when we don&#39;t have colors</span>
PS1<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;\u@\h \W \$ &#39;</span>
<span style="color:#66d9ef">else</span>
PS1<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;\u@\h \w \$ &#39;</span>
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">fi</span>
unset use_color safe_term match_lhs sh
</code></pre></div><h4 id="settings">Settings</h4>
<p>Some general bash settings.</p>
<p>References:</p>
<ul>
<li><a href="https://www.gnu.org/software/bash/manual/html%5Fnode/The-Shopt-Builtin.html">shopt list</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">complete -cf sudo <span style="color:#75715e"># Sudo autocompletion</span>
shopt -s checkwinsize <span style="color:#75715e"># Check windows size after each command</span>
shopt -s expand_aliases <span style="color:#75715e"># Aliases</span>
shopt -s autocd <span style="color:#75715e"># Cd to directory just by typing its name (without cd)</span>
</code></pre></div><p>History control</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">shopt -s histappend
export HISTCONTROL<span style="color:#f92672">=</span>ignoredups:erasedups
HISTSIZE<span style="color:#f92672">=</span>
HISTFILESIZE<span style="color:#f92672">=</span>
</code></pre></div><p>Autocompletions</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#f92672">[</span> -r /usr/share/bash-completion/bash_completion <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> . /usr/share/bash-completion/bash_completion
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -d <span style="color:#e6db74">&#34;/usr/share/fzf&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
source /usr/share/fzf/completion.bash
source /usr/share/fzf/key-bindings.bash
<span style="color:#66d9ef">fi</span>
</code></pre></div><h4 id="aliases">Aliases</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">alias v<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;vim&#34;</span>
alias gg<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;lazygit&#34;</span>
alias ls<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;exa --icons&#34;</span>
alias ll<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;exa -lah --icons&#34;</span>
alias q<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;exit&#34;</span>
alias c<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;clear&#34;</span>
alias ci<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;init_conda&#34;</span>
alias ca<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;conda activate&#34;</span>
alias cii<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;export INIT_CONDA=true &amp;&amp; init_conda&#34;</span>
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> ! -z <span style="color:#e6db74">&#34;</span>$SIMPLE<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
unalias ls
alias ll<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;ls -lah&#34;</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><h4 id="anaconda">Anaconda</h4>
<blockquote>
<p>managed by &lsquo;conda init&rsquo; !!!</p>
</blockquote>
<p>Yeah, tell this to yourself</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">init_conda <span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
__conda_setup<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span><span style="color:#e6db74">&#39;/home/pavel/.guix-extra-profiles/dev/dev/bin/conda&#39;</span> <span style="color:#e6db74">&#39;shell.bash&#39;</span> <span style="color:#e6db74">&#39;hook&#39;</span> 2&gt; /dev/null<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> $? -eq <span style="color:#ae81ff">0</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
eval <span style="color:#e6db74">&#34;</span>$__conda_setup<span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">else</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -f <span style="color:#e6db74">&#34;/home/pavel/.guix-extra-profiles/dev/dev/etc/profile.d/conda.sh&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
. <span style="color:#e6db74">&#34;/home/pavel/.guix-extra-profiles/dev/dev/etc/profile.d/conda.sh&#34;</span>
<span style="color:#66d9ef">else</span>
<span style="color:#75715e"># export PATH=&#34;/home/pavel/Programs/miniconda3/bin:$PATH&#34;</span>
echo <span style="color:#e6db74">&#34;what&#34;</span>
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">fi</span>
unset __conda_setup
<span style="color:#f92672">}</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> ! -z <span style="color:#e6db74">&#34;</span>$INIT_CONDA<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
init_conda
<span style="color:#66d9ef">fi</span>
</code></pre></div><h4 id="starship-prompt">Starship prompt</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> -z <span style="color:#e6db74">&#34;</span>$SIMPLE<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
eval <span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>starship init bash<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><h2 id="fish">Fish</h2>
<table>
<thead>
<tr>
<th>Guix dependency</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>fish</td>
<td>An alternative non POSIX-compliant shell</td>
</tr>
</tbody>
</table>
<p><a href="https://fishshell.com/">Fish shell</a> is a non-POSIX-compliant shell, which offers some fancy UI &amp; UX features.</p>
<p>Launch starship</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-fish" data-lang="fish"><span style="color:#a6e22e">starship</span> init fish <span style="color:#f92672">|</span> source
</code></pre></div><p>Enable vi keybindings &amp; aliases. The alias syntax is the same as in bash, so it&rsquo;s just a noweb reference to <code>.bashrc</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-fish" data-lang="fish"><span style="color:#a6e22e">fish_vi_key_bindings</span>
<span style="color:#e6db74">&lt;&lt;shell-alias</span>es<span style="color:#f92672">&gt;&gt;</span>
</code></pre></div><table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>dt-colorscripts</td>
</tr>
</tbody>
</table>
<p>Launch a random <a href="https://gitlab.com/dwt1/shell-color-scripts">DT&rsquo;s colorscript</a> unless ran inside tmux or Emacs.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-fish" data-lang="fish"><span style="color:#66d9ef">if</span> ! test <span style="color:#a6e22e">-n</span> <span style="color:#e6db74">&#34;</span>$TMUX<span style="color:#e6db74">&#34;</span>; <span style="color:#66d9ef">and</span> ! test <span style="color:#a6e22e">-n</span> <span style="color:#e6db74">&#34;</span>$IS_EMACS<span style="color:#e6db74">&#34;</span>;
<span style="color:#a6e22e">colorscript</span> random
<span style="color:#66d9ef">end</span>
</code></pre></div><p>Suppress fish greeting</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-fish" data-lang="fish"><span style="color:#66d9ef">set</span> fish_greeting
</code></pre></div><h3 id="anaconda">Anaconda</h3>
<p>First, a function to initialize anaconda.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-fish" data-lang="fish"><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">init_conda</span>
eval /home/pavel/.guix<span style="color:#a6e22e">-extra-profiles</span>/dev/dev/bin/conda <span style="color:#e6db74">&#34;shell.fish&#34;</span> <span style="color:#e6db74">&#34;hook&#34;</span> $argv <span style="color:#f92672">|</span> source
<span style="color:#66d9ef">end</span>
<span style="color:#66d9ef">if</span> <span style="color:#66d9ef">test</span> <span style="color:#a6e22e">-n</span> <span style="color:#e6db74">&#34;</span>$INIT_CONDA<span style="color:#e6db74">&#34;</span>;
<span style="color:#a6e22e">init_conda</span>
<span style="color:#66d9ef">end</span>
</code></pre></div><p>Then, check if launched from Emacs with environment activated.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-fish" data-lang="fish"><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">test</span> <span style="color:#a6e22e">-n</span> <span style="color:#e6db74">&#34;</span>$EMACS_CONDA_ENV<span style="color:#e6db74">&#34;</span>;
<span style="color:#a6e22e">conda</span> activate $EMACS_CONDA_ENV
<span style="color:#66d9ef">end</span>
</code></pre></div><h3 id="colors">Colors</h3>
<p>Fish seems to have hardcoded colorcodes in some color settings. I set these to base16 colors so they would match Xresources.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-fish" data-lang="fish"><span style="color:#66d9ef">set</span> fish_color_command cyan
<span style="color:#66d9ef">set</span> fish_color_comment green
<span style="color:#66d9ef">set</span> fish_color_end white
<span style="color:#66d9ef">set</span> fish_color_error red
<span style="color:#66d9ef">set</span> fish_color_escape yellow
<span style="color:#66d9ef">set</span> fish_color_operator yellow
<span style="color:#66d9ef">set</span> fish_color_param magenta
<span style="color:#66d9ef">set</span> fish_color_quote brwhite
<span style="color:#66d9ef">set</span> fish_color_redirection yellow
</code></pre></div><h3 id="keybindings">Keybindings</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-fish" data-lang="fish">bind <span style="color:#a6e22e">-M</span> insert <span style="color:#ae81ff">\e</span>l forward<span style="color:#a6e22e">-char</span>
bind <span style="color:#a6e22e">-M</span> insert <span style="color:#ae81ff">\e</span>h backward<span style="color:#a6e22e">-char</span>
bind <span style="color:#a6e22e">-M</span> insert <span style="color:#ae81ff">\e</span>w forward<span style="color:#a6e22e">-word</span>
bind <span style="color:#a6e22e">-M</span> insert <span style="color:#ae81ff">\e</span>b backward<span style="color:#a6e22e">-word</span>
</code></pre></div><h2 id="nushell">Nushell</h2>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>nushell-bin</td>
</tr>
</tbody>
</table>
<p>A structured shell. I don&rsquo;t use it as of now, but perhaps one day.</p>
<p>Set starship prompt</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-toml" data-lang="toml"><span style="color:#a6e22e">startup</span> = [
<span style="color:#960050;background-color:#1e0010">&lt;&lt;</span><span style="color:#a6e22e">nu-aliases</span><span style="color:#960050;background-color:#1e0010">&gt;&gt;</span>,
<span style="color:#e6db74">&#34;mkdir ~/.cache/starship&#34;</span>,
<span style="color:#e6db74">&#34;starship init nu | save ~/.cache/starship/init.nu&#34;</span>,
<span style="color:#e6db74">&#34;source ~/.cache/starship/init.nu&#34;</span>,
]
<span style="color:#a6e22e">prompt</span> = <span style="color:#e6db74">&#34;starship_prompt&#34;</span>
</code></pre></div><p>Skip welcome message</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-toml" data-lang="toml"><span style="color:#a6e22e">skip_welcome_message</span> = <span style="color:#66d9ef">true</span>
</code></pre></div><p>Set table mode</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-toml" data-lang="toml"><span style="color:#a6e22e">table_mode</span> = <span style="color:#e6db74">&#34;rounded&#34;</span>
</code></pre></div><p>Aliases</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-toml" data-lang="toml"><span style="color:#e6db74">&#34;alias ll = ls -l&#34;</span>,
<span style="color:#e6db74">&#34;alias c = clear&#34;</span>,
<span style="color:#e6db74">&#34;alias q = exit&#34;</span>
</code></pre></div><p>Colors</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-toml" data-lang="toml">[<span style="color:#a6e22e">color_config</span>]
<span style="color:#a6e22e">primitive_filesize</span>=<span style="color:#e6db74">&#34;ub&#34;</span>
<span style="color:#a6e22e">primitive_boolean</span>=<span style="color:#e6db74">&#34;yu&#34;</span>
<span style="color:#a6e22e">primitive_duration</span>=<span style="color:#e6db74">&#34;g&#34;</span>
<span style="color:#a6e22e">primitive_path</span>=<span style="color:#e6db74">&#34;y&#34;</span>
<span style="color:#a6e22e">primitive_date</span>=<span style="color:#e6db74">&#34;r&#34;</span>
<span style="color:#a6e22e">primitive_int</span>=<span style="color:#e6db74">&#34;c&#34;</span>
<span style="color:#a6e22e">primitive_decimal</span>=<span style="color:#e6db74">&#34;c&#34;</span>
</code></pre></div><h2 id="starship-prompt">Starship prompt</h2>
<table>
<thead>
<tr>
<th>Guix dependency</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>rust-starship</td>
<td>my prompt of choice</td>
</tr>
</tbody>
</table>
<p><a href="https://starship.rs/">Starship</a> is a nice cross-shell prompt, written in Rust.</p>
<p>References:</p>
<ul>
<li><a href="https://starship.rs/config/">Startship config guide</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-toml" data-lang="toml">[<span style="color:#a6e22e">character</span>]
<span style="color:#a6e22e">success_symbol</span> = <span style="color:#e6db74">&#34;[➤ ](bold green)&#34;</span>
<span style="color:#a6e22e">error_symbol</span> = <span style="color:#e6db74">&#34;[ ](bold red)&#34;</span>
<span style="color:#a6e22e">vicmd_symbol</span> = <span style="color:#e6db74">&#34;[ᐊ ](bold green)&#34;</span>
[<span style="color:#a6e22e">aws</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
<span style="color:#75715e"># [battery]</span>
<span style="color:#75715e"># full_symbol = &#34;&#34;</span>
<span style="color:#75715e"># charging_symbol = &#34;&#34;</span>
<span style="color:#75715e"># discharging_symbol = &#34;&#34;</span>
[<span style="color:#a6e22e">conda</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">cmd_duration</span>]
<span style="color:#a6e22e">min_time</span> = <span style="color:#ae81ff">500</span>
<span style="color:#a6e22e">format</span> = <span style="color:#e6db74">&#34; [$duration]($style) &#34;</span>
[<span style="color:#a6e22e">docker_context</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">elixir</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">elm</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">git_branch</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
<span style="color:#a6e22e">truncation_length</span> = <span style="color:#ae81ff">20</span>
[<span style="color:#a6e22e">golang</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
<span style="color:#75715e"># [haskell]</span>
<span style="color:#75715e"># symbol = &#34;&#34;</span>
[<span style="color:#a6e22e">hg_branch</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">java</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">julia</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">memory_usage</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">nim</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">nix_shell</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">nodejs</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">package</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
<span style="color:#a6e22e">disabled</span> = <span style="color:#66d9ef">true</span>
[<span style="color:#a6e22e">php</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">python</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">ruby</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
[<span style="color:#a6e22e">rust</span>]
<span style="color:#a6e22e">symbol</span> = <span style="color:#e6db74">&#34;&#34;</span>
</code></pre></div><h2 id="tmux">Tmux</h2>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>tmux</td>
</tr>
<tr>
<td>python-tmuxp</td>
</tr>
</tbody>
</table>
<p><a href="https://github.com/tmux/tmux">tmux</a> is my terminal multiplexer of choice.</p>
<p>It provides pretty sane defaults, so the config is not too large. I rebind the prefix to <code>C-a</code> though.</p>
<h3 id="term-settings">Term settings</h3>
<p>I have no idea how and why these two work.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">default</span>-<span style="color:#a6e22e">terminal</span> <span style="color:#e6db74">&#34;screen-256color&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">ga</span> <span style="color:#a6e22e">terminal</span>-<span style="color:#a6e22e">overrides</span> <span style="color:#e6db74">&#34;,*256col*:Tc&#34;</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div><p>History limit.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">history</span>-<span style="color:#a6e22e">limit</span> <span style="color:#ae81ff">20000</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div><h3 id="keybindings">Keybindings</h3>
<p>Enable vi keys and mouse.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"><span style="color:#a6e22e">set</span>-<span style="color:#a6e22e">window</span>-<span style="color:#a6e22e">option</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">mode</span>-<span style="color:#a6e22e">keys</span> <span style="color:#a6e22e">vi</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span>-<span style="color:#a6e22e">option</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">xterm</span>-<span style="color:#a6e22e">keys</span> <span style="color:#a6e22e">on</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span>-<span style="color:#a6e22e">option</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">mouse</span> <span style="color:#a6e22e">on</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">sg</span> <span style="color:#a6e22e">escape</span>-<span style="color:#a6e22e">time</span> <span style="color:#ae81ff">10</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div><p>Change prefix from <code>C-b</code> to <code>C-a</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"><span style="color:#a6e22e">unbind</span> <span style="color:#a6e22e">C</span>-<span style="color:#a6e22e">b</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">prefix</span> <span style="color:#a6e22e">C</span>-<span style="color:#a6e22e">a</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">C</span>-<span style="color:#a6e22e">a</span> <span style="color:#a6e22e">send</span>-<span style="color:#a6e22e">prefix</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div><p>Vi-like keybindings to manage panes &amp; windows.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">h</span> <span style="color:#a6e22e">select</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">L</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">j</span> <span style="color:#a6e22e">select</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">D</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">k</span> <span style="color:#a6e22e">select</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">U</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">l</span> <span style="color:#a6e22e">select</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">R</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">s</span> <span style="color:#a6e22e">split</span>-<span style="color:#a6e22e">window</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">v</span> <span style="color:#a6e22e">split</span>-<span style="color:#a6e22e">window</span> -<span style="color:#a6e22e">h</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> <span style="color:#a6e22e">n</span> <span style="color:#a6e22e">new</span>-<span style="color:#a6e22e">window</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> <span style="color:#a6e22e">t</span> <span style="color:#a6e22e">next</span>-<span style="color:#a6e22e">window</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> <span style="color:#a6e22e">T</span> <span style="color:#a6e22e">previous</span>-<span style="color:#a6e22e">window</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div><p>Reload the config.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">r</span> <span style="color:#a6e22e">source</span>-<span style="color:#a6e22e">file</span> ~/.<span style="color:#a6e22e">tmux</span>.<span style="color:#a6e22e">conf</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div><h3 id="copy-to-clipboard">Copy to clipboard</h3>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>xclip</td>
</tr>
</tbody>
</table>
<p>Make tmux copying copy to clipboard as well</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"><span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> -<span style="color:#a6e22e">T</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">mode</span>-<span style="color:#a6e22e">vi</span> <span style="color:#a6e22e">MouseDragEnd1Pane</span> <span style="color:#a6e22e">send</span>-<span style="color:#a6e22e">keys</span> -<span style="color:#a6e22e">X</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">pipe</span>-<span style="color:#a6e22e">and</span>-<span style="color:#a6e22e">cancel</span> <span style="color:#e6db74">&#34;xclip -selection clipboard -i&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> -<span style="color:#a6e22e">T</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">mode</span>-<span style="color:#a6e22e">vi</span> <span style="color:#a6e22e">y</span> <span style="color:#a6e22e">send</span>-<span style="color:#a6e22e">keys</span> -<span style="color:#a6e22e">X</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">pipe</span>-<span style="color:#a6e22e">and</span>-<span style="color:#a6e22e">cancel</span> <span style="color:#e6db74">&#34;xclip -selection clipboard -i&#34;</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div><h3 id="ui">UI</h3>
<p>I generated the following with <a href="https://github.com/edkolev/tmuxline.vim">tmuxline.vim</a> plugin and palenight theme for <a href="https://github.com/vim-airline/vim-airline">vim-airline</a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"># <span style="color:#a6e22e">This</span> <span style="color:#a6e22e">tmux</span> <span style="color:#a6e22e">statusbar</span> <span style="color:#a6e22e">config</span> <span style="color:#a6e22e">was</span> <span style="color:#a6e22e">created</span> <span style="color:#a6e22e">by</span> <span style="color:#a6e22e">tmuxline</span>.<span style="color:#a6e22e">vim</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span># <span style="color:#a6e22e">on</span> <span style="color:#a6e22e">Wed</span>, <span style="color:#ae81ff">22</span> <span style="color:#a6e22e">Jan</span> <span style="color:#ae81ff">2020</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">status</span>-<span style="color:#a6e22e">justify</span> <span style="color:#e6db74">&#34;centre&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">status</span> <span style="color:#e6db74">&#34;on&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">status</span>-<span style="color:#a6e22e">left</span>-<span style="color:#a6e22e">style</span> <span style="color:#e6db74">&#34;none&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">message</span>-<span style="color:#a6e22e">command</span>-<span style="color:#a6e22e">style</span> <span style="color:#e6db74">&#34;fg=#bfc7d5,bg=#474b59&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">status</span>-<span style="color:#a6e22e">right</span>-<span style="color:#a6e22e">style</span> <span style="color:#e6db74">&#34;none&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">pane</span>-<span style="color:#a6e22e">active</span>-<span style="color:#a6e22e">border</span>-<span style="color:#a6e22e">style</span> <span style="color:#e6db74">&#34;fg=#939ede&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">status</span>-<span style="color:#a6e22e">style</span> <span style="color:#e6db74">&#34;none,bg=#333747&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">message</span>-<span style="color:#a6e22e">style</span> <span style="color:#e6db74">&#34;fg=#bfc7d5,bg=#474b59&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">pane</span>-<span style="color:#a6e22e">border</span>-<span style="color:#a6e22e">style</span> <span style="color:#e6db74">&#34;fg=#474b59&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">status</span>-<span style="color:#a6e22e">right</span>-<span style="color:#a6e22e">length</span> <span style="color:#e6db74">&#34;100&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">status</span>-<span style="color:#a6e22e">left</span>-<span style="color:#a6e22e">length</span> <span style="color:#e6db74">&#34;100&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">setw</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">window</span>-<span style="color:#a6e22e">status</span>-<span style="color:#a6e22e">activity</span>-<span style="color:#a6e22e">style</span> <span style="color:#e6db74">&#34;none,fg=#939ede,bg=#333747&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">setw</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">window</span>-<span style="color:#a6e22e">status</span>-<span style="color:#a6e22e">separator</span> <span style="color:#e6db74">&#34;&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">setw</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">window</span>-<span style="color:#a6e22e">status</span>-<span style="color:#a6e22e">style</span> <span style="color:#e6db74">&#34;none,fg=#bfc7d5,bg=#333747&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">status</span>-<span style="color:#a6e22e">left</span> <span style="color:#e6db74">&#34;#[fg=#292D3E,bg=#939ede] #S #[fg=#939ede,bg=#474b59,nobold,nounderscore,noitalics]#[fg=#bfc7d5,bg=#474b59] #W #[fg=#474b59,bg=#333747,nobold,nounderscore,noitalics]&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">set</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">status</span>-<span style="color:#a6e22e">right</span> <span style="color:#e6db74">&#34;#[fg=#333747,bg=#333747,nobold,nounderscore,noitalics]#[fg=#bfc7d5,bg=#333747] %-H:%M #[fg=#474b59,bg=#333747,nobold,nounderscore,noitalics]#[fg=#bfc7d5,bg=#474b59] %a, %b %d #[fg=#939ede,bg=#474b59,nobold,nounderscore,noitalics]#[fg=#292D3E,bg=#939ede] #H &#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">setw</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">window</span>-<span style="color:#a6e22e">status</span>-<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;#[fg=#333747,bg=#333747,nobold,nounderscore,noitalics]#[default] #I #W #[align=left] #[fg=#333747,bg=#333747,nobold,nounderscore,noitalics]&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">setw</span> -<span style="color:#a6e22e">g</span> <span style="color:#a6e22e">window</span>-<span style="color:#a6e22e">status</span>-<span style="color:#a6e22e">current</span>-<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;#[fg=#333747,bg=#474b59,nobold,nounderscore,noitalics]#[fg=#bfc7d5,bg=#474b59] #I #W #[fg=#474b59,bg=#333747,nobold,nounderscore,noitalics]&#34;</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div><p>Source the line config:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"><span style="color:#a6e22e">source</span> ~/.<span style="color:#a6e22e">tmux</span>.<span style="color:#a6e22e">line</span>.<span style="color:#a6e22e">conf</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div><h2 id="alacritty">Alacritty</h2>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>alacritty</td>
</tr>
</tbody>
</table>
<p><a href="https://github.com/alacritty/alacritty">Alacritty</a> is a GPU-accelerated terminal emulator. I haven&rsquo;t found it to be an inch faster than st, but configuration the in yml format is way more convinient than patches.</p>
<p>Once again, we have an application which doesn&rsquo;t support reading Xresources, so here goes noweb.</p>
<p><a id="code-snippet--get-xrdb"></a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">xrdb -query all | grep <span style="color:#e6db74">&#34;</span>$color<span style="color:#e6db74">:&#34;</span> | cut -f <span style="color:#ae81ff">2</span>
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq-local org-confirm-babel-evaluate <span style="color:#66d9ef">nil</span>)
</code></pre></div><p>References:</p>
<ul>
<li><a href="https://github.com/alacritty/alacritty/blob/master/alacritty.yml">default config</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#f92672">decorations</span>: <span style="color:#ae81ff">none</span>
<span style="color:#f92672">font</span>:
<span style="color:#f92672">normal</span>:
<span style="color:#f92672">family</span>: <span style="color:#ae81ff">JetBrainsMono Nerd Font</span>
<span style="color:#f92672">style</span>: <span style="color:#ae81ff">Regular</span>
<span style="color:#f92672">size</span>: <span style="color:#ae81ff">10</span>
<span style="color:#f92672">env</span>:
<span style="color:#f92672">TERM</span>: <span style="color:#ae81ff">xterm-256color</span>
<span style="color:#f92672">colors</span>:
<span style="color:#f92672">primary</span>:
<span style="color:#f92672">background</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color0&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">foreground</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color7&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">normal</span>:
<span style="color:#f92672">black</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color0&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">red</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color1&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">green</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color2&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">yellow</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color3&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">blue</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color4&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">magenta</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color5&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">cyan</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color6&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">white</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color7&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">bright</span>:
<span style="color:#f92672">Black</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color8&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">Red</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color9&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">Green</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color10&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">Yellow</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color11&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">Blue</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color12&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">Magenta</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color13&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">Cyan</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color14&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">White</span>: <span style="color:#e6db74">&#39;&lt;&lt;get-xrdb(color=&#34;color15&#34;)&gt;&gt;&#39;</span>
<span style="color:#f92672">background_opacity</span>: <span style="color:#ae81ff">0.80</span>
<span style="color:#f92672">window</span>:
<span style="color:#f92672">padding</span>:
<span style="color:#f92672">x</span>: <span style="color:#ae81ff">0</span>
<span style="color:#f92672">y</span>: <span style="color:#ae81ff">0</span>
<span style="color:#f92672">dynamic_padding</span>: <span style="color:#66d9ef">true</span>
<span style="color:#f92672">key_bindings</span>:
- { <span style="color:#f92672">key: Paste, action</span>: <span style="color:#ae81ff">Paste }</span>
- { <span style="color:#f92672">key: Copy, action</span>: <span style="color:#ae81ff">Copy }</span>
- { <span style="color:#f92672">key: L, mods: Control, action</span>: <span style="color:#ae81ff">ClearLogNotice }</span>
- { <span style="color:#f92672">key: L, mods: Control, mode: ~Vi|~Search, chars</span>: <span style="color:#e6db74">&#34;\x0c&#34;</span> }
- { <span style="color:#f92672">key: PageUp, mods: Shift, mode: ~Alt, action</span>: <span style="color:#ae81ff">ScrollPageUp, }</span>
- { <span style="color:#f92672">key: PageDown, mods: Shift, mode: ~Alt, action</span>: <span style="color:#ae81ff">ScrollPageDown }</span>
- { <span style="color:#f92672">key: Home, mods: Shift, mode: ~Alt, action</span>: <span style="color:#ae81ff">ScrollToTop, }</span>
- { <span style="color:#f92672">key: End, mods: Shift, mode: ~Alt, action</span>: <span style="color:#ae81ff">ScrollToBottom }</span>
<span style="color:#75715e"># Turn off vi mode</span>
- { <span style="color:#f92672">key: Space, mods: Shift|Control, mode: ~Search, action</span>: <span style="color:#ae81ff">ReceiveChar }</span>
<span style="color:#75715e"># (Windows, Linux, and BSD only)</span>
- { <span style="color:#f92672">key: V, mods: Control|Shift, mode: ~Vi, action</span>: <span style="color:#ae81ff">Paste }</span>
- { <span style="color:#f92672">key: C, mods: Control|Shift, action</span>: <span style="color:#ae81ff">Copy }</span>
- { <span style="color:#f92672">key: F, mods: Control|Shift, mode: ~Search, action</span>: <span style="color:#ae81ff">ReceiveChar }</span>
- { <span style="color:#f92672">key: B, mods: Control|Shift, mode: ~Search, action</span>: <span style="color:#ae81ff">ReceiveChar }</span>
- { <span style="color:#f92672">key: Insert, mods: Shift, action</span>: <span style="color:#ae81ff">PasteSelection }</span>
- { <span style="color:#f92672">key: Key0, mods: Control, action</span>: <span style="color:#ae81ff">ResetFontSize }</span>
- { <span style="color:#f92672">key: Equals, mods: Control, action</span>: <span style="color:#ae81ff">IncreaseFontSize }</span>
- { <span style="color:#f92672">key: Plus, mods: Control, action</span>: <span style="color:#ae81ff">IncreaseFontSize }</span>
- { <span style="color:#f92672">key: NumpadAdd, mods: Control, action</span>: <span style="color:#ae81ff">IncreaseFontSize }</span>
- { <span style="color:#f92672">key: Minus, mods: Control, action</span>: <span style="color:#ae81ff">DecreaseFontSize }</span>
- { <span style="color:#f92672">key: NumpadSubtract, mods: Control, action</span>: <span style="color:#ae81ff">DecreaseFontSize }</span>
</code></pre></div><h2 id="various-console-applications">Various console applications</h2>
<table>
<thead>
<tr>
<th>Guix dependency</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>ncurses</td>
<td>Provides stuff like <code>clear</code></td>
</tr>
<tr>
<td>exa</td>
<td><code>ls</code> replacement, written in Rust</td>
</tr>
<tr>
<td>bat</td>
<td><code>cat</code> clone with syntax highlighting</td>
</tr>
<tr>
<td>htop</td>
<td>Interactive process viewer</td>
</tr>
<tr>
<td>nethogs</td>
<td>A tool to group processed by used bandwidth</td>
</tr>
<tr>
<td>osync</td>
<td>rsync wrapper</td>
</tr>
<tr>
<td>neofetch</td>
<td>Fetch system info</td>
</tr>
<tr>
<td>fzf</td>
<td>fuzzy finder</td>
</tr>
<tr>
<td>p7zip</td>
<td>archiver</td>
</tr>
<tr>
<td>password-store</td>
<td>CLI password manager</td>
</tr>
<tr>
<td>unzip</td>
<td></td>
</tr>
<tr>
<td>jmtpfs</td>
<td>A tool to mount MTP devices (e.g. Android)</td>
</tr>
<tr>
<td>tokei</td>
<td>Count lines of code</td>
</tr>
</tbody>
</table>
<h2 id="misc-scripts">Misc scripts</h2>
<h3 id="nt-exec-command-with-a-finished-notification"><code>nt</code> - exec command with a finished notification</h3>
<p>Usage:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">nt &lt;command&gt;
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">command<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$@<span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> ! -z <span style="color:#e6db74">&#34;</span>$command<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
start_time<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>date -u +%s<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>
$command
end_time<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>date -u +%s<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>
elapsed<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$((</span>$end_time<span style="color:#f92672">-</span>$start_time<span style="color:#66d9ef">))</span><span style="color:#e6db74">&#34;</span>
notify-send <span style="color:#e6db74">&#34;Terminal&#34;</span> <span style="color:#e6db74">&#34;Command\n</span>$command<span style="color:#e6db74">\nexecuted in </span>$elapsed<span style="color:#e6db74"> seconds&#34;</span>
<span style="color:#66d9ef">else</span>
notify-send <span style="color:#e6db74">&#34;Terminal&#34;</span> <span style="color:#e6db74">&#34;Command execution complete&#34;</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><h3 id="autocommmit"><code>autocommmit</code></h3>
<p>A script to autocommit files in a repository. I use it to sync my org directory and password store. I guess it&rsquo;s not how git is intended to be used, but it works for me.</p>
<p>Usage:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">autocommit &lt;repository&gt; [-F]
</code></pre></div><p>Environment:</p>
<table>
<thead>
<tr>
<th>Variable</th>
<th>Description</th>
<th>Default value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>TIMEOUT_MIN</code></td>
<td>Default timeout</td>
<td>60</td>
</tr>
</tbody>
</table>
<p>Here&rsquo;s more or less what the script is doing:</p>
<ul>
<li>If there is a merge conflict, notify</li>
<li>If there are changed files in the last <code>TIMEOUT_MIN</code> minutes, commit</li>
<li>Fetch</li>
<li>If there are were changes in the last <code>TTMEOUT_MIN</code>, merge (usually the merge has to be fast-forward)</li>
<li>If fetch was successful &amp; merge was successful or delayed because of changes in the last <code>TIMEOUT_MIN</code>, push</li>
<li>Send a notification about the events above</li>
<li>Send a separate notification if there is a merge conflict</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">TIMEOUT_MIN<span style="color:#f92672">=</span><span style="color:#e6db74">${</span>TIMEOUT_MIN<span style="color:#66d9ef">:-</span>60<span style="color:#e6db74">}</span>
export DISPLAY<span style="color:#f92672">=</span>:0
cd <span style="color:#e6db74">&#34;</span>$1<span style="color:#e6db74">&#34;</span>
TIMESTAMP<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>date +%s<span style="color:#66d9ef">)</span>
LAST_COMMIT_TIMESTAMP<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>git log -1 --format<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;%at&#34;</span> | xargs -I<span style="color:#f92672">{}</span> date -d @<span style="color:#f92672">{}</span> +%s<span style="color:#66d9ef">)</span>
RECENTLY_CHANGED_NUM<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>find . -not -path <span style="color:#e6db74">&#39;*/\.*&#39;</span> -mmin -$TIMEOUT_MIN | wc -l<span style="color:#66d9ef">)</span>
CHANGED_NUM<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>git status --porcelain | wc -l<span style="color:#66d9ef">)</span>
COMMITED<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;No&#34;</span>
PUSHED<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;No&#34;</span>
FETCHED<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;No&#34;</span>
MERGED<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;No&#34;</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> <span style="color:#66d9ef">$(</span>git ls-files -u | wc -l<span style="color:#66d9ef">)</span> -gt <span style="color:#ae81ff">0</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
notify-send -u critical <span style="color:#e6db74">&#34;Autocommit </span><span style="color:#66d9ef">$(</span>pwd<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;Merge conflict!&#34;</span>
exit
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> <span style="color:#f92672">(</span>$RECENTLY_CHANGED_NUM -eq <span style="color:#ae81ff">0</span> <span style="color:#f92672">||</span> $2 <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;-F&#34;</span><span style="color:#f92672">)</span> <span style="color:#f92672">&amp;&amp;</span> $CHANGED_NUM -gt <span style="color:#ae81ff">0</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
read -r -d <span style="color:#e6db74">&#39;&#39;</span> MESSAGE <span style="color:#e6db74">&lt;&lt; EOM
</span><span style="color:#e6db74">Autocommit $(date -Iminutes)
</span><span style="color:#e6db74">
</span><span style="color:#e6db74">Hostname: $(hostname)
</span><span style="color:#e6db74">EOM</span>
git add -A
git commit -m <span style="color:#e6db74">&#34;</span>$MESSAGE<span style="color:#e6db74">&#34;</span>
COMMITED<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Yes&#34;</span>
<span style="color:#66d9ef">fi</span>
NEED_TO_PUSH<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>git log origin/master..HEAD | wc -l<span style="color:#66d9ef">)</span>
git fetch <span style="color:#f92672">&amp;&amp;</span> FETCHED<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Yes&#34;</span> <span style="color:#f92672">||</span> FETCHED<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;No&#34;</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> $RECENTLY_CHANGED_NUM -gt <span style="color:#ae81ff">0</span> <span style="color:#f92672">&amp;&amp;</span> $2 !<span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;-F&#39;</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
MERGED<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Waiting&#34;</span>
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> <span style="color:#f92672">(</span>$RECENTLY_CHANGED_NUM -eq <span style="color:#ae81ff">0</span> <span style="color:#f92672">||</span> $2 <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;-F&#34;</span><span style="color:#f92672">)</span> <span style="color:#f92672">&amp;&amp;</span> $FETCHED <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Yes&#34;</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
MERGE_OUT<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>git merge origin/master<span style="color:#66d9ef">)</span> <span style="color:#f92672">&amp;&amp;</span> MERGED<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Yes&#34;</span> <span style="color:#f92672">||</span> MERGED<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;No&#34;</span>
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> $NEED_TO_PUSH -gt <span style="color:#ae81ff">0</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#f92672">(</span>$MERGED <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Yes&#34;</span> <span style="color:#f92672">||</span> $MERGED <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Waiting&#34;</span><span style="color:#f92672">)</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
git push origin <span style="color:#f92672">&amp;&amp;</span> PUSHED<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Yes&#34;</span> <span style="color:#f92672">||</span> PUSHED<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;No&#34;</span>
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> $PUSHED <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Yes&#34;</span> <span style="color:#f92672">||</span> $COMMITED <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Yes&#34;</span> <span style="color:#f92672">||</span> <span style="color:#f92672">(</span>$MERGED <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Yes&#34;</span> <span style="color:#f92672">&amp;&amp;</span> $MERGE_OUT !<span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Already up to date.&#34;</span><span style="color:#f92672">)]]</span>; <span style="color:#66d9ef">then</span>
read -r -d <span style="color:#e6db74">&#39;&#39;</span> NOTIFICATION <span style="color:#e6db74">&lt;&lt; EOM
</span><span style="color:#e6db74">Commited: $COMMITED
</span><span style="color:#e6db74">Fetched: $FETCHED
</span><span style="color:#e6db74">Merged: $MERGED
</span><span style="color:#e6db74">Pushed: $PUSHED
</span><span style="color:#e6db74">EOM</span>
notify-send <span style="color:#e6db74">&#34;Autocommit </span><span style="color:#66d9ef">$(</span>pwd<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;</span>$NOTIFICATION<span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> <span style="color:#66d9ef">$(</span>git ls-files -u | wc -l<span style="color:#66d9ef">)</span> -gt <span style="color:#ae81ff">0</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
notify-send -u critical <span style="color:#e6db74">&#34;Autocommit </span><span style="color:#66d9ef">$(</span>pwd<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;Merge conflict!&#34;</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><p><code>mcron</code> job:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#a6e22e">job</span> <span style="color:#e6db74">&#34;0 * * * *&#34;</span> <span style="color:#e6db74">&#34;autocommit ~/Documents/org-mode&#34;</span>)
(<span style="color:#a6e22e">job</span> <span style="color:#e6db74">&#34;0,15,30,45 * * * *&#34;</span> <span style="color:#e6db74">&#34;autocommit ~/.password-store&#34;</span>)
</code></pre></div><h2 id="guix-settings">Guix settings</h2>
<p><a id="code-snippet--packages"></a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(my/format-guix-dependencies)
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#a6e22e">specifications-&gt;manifest</span>
<span style="color:#f92672">&#39;</span>(
&lt;&lt;packages()&gt;&gt;))
</code></pre></div><h2 id="android-notes">Android notes</h2>
<p>SSH instructions: <a href="https://wiki.termux.com/wiki/Remote%5FAccess">https://wiki.termux.com/wiki/Remote%5FAccess</a></p>
<p>Don&rsquo;t forget to install the following termux packages:</p>
<table>
<thead>
<tr>
<th>Termux package</th>
</tr>
</thead>
<tbody>
<tr>
<td>vim</td>
</tr>
<tr>
<td>tmux</td>
</tr>
<tr>
<td>starship</td>
</tr>
<tr>
<td>fish</td>
</tr>
<tr>
<td>exa</td>
</tr>
<tr>
<td>bat</td>
</tr>
<tr>
<td>git</td>
</tr>
</tbody>
</table>
<p>Also:</p>
<ul>
<li>cleanup <code>$PREFIX/etc/motd</code> to remove hello message.</li>
<li>copy the required font at <code>$HOME/.termux/font.ttf</code> and run <code>termux-reload-settings</code>.</li>
</ul>
<h3 id="installation-of-dt-s-colorscripts">Installation of <a href="https://gitlab.com/dwt1/shell-color-scripts">DT&rsquo;s colorscripts</a>:</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">git clone https://gitlab.com/dwt1/shell-color-scripts.git
cd shell-color-scripts
</code></pre></div><p>Apply a patch:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-diff" data-lang="diff"><span style="color:#f92672">--- a/colorscript.sh
</span><span style="color:#f92672"></span><span style="color:#a6e22e">+++ b/colorscript.sh
</span><span style="color:#a6e22e"></span><span style="color:#75715e">@@ -2,7 +2,7 @@
</span><span style="color:#75715e"></span>
# Simple CLI for shell-color-scripts
<span style="color:#f92672">-DIR_COLORSCRIPTS=&#34;/opt/shell-color-scripts/colorscripts&#34;
</span><span style="color:#f92672"></span><span style="color:#a6e22e">+DIR_COLORSCRIPTS=&#34;$PREFIX/opt/shell-color-scripts/colorscripts&#34;
</span><span style="color:#a6e22e"></span> LS_CMD=&#34;$(command -v ls)&#34;
fmt_help=&#34; %-20s\t%-54s\n&#34;
list_colorscripts=&#34;$($LS_CMD &#34;${DIR_COLORSCRIPTS}&#34; | cut -d &#39; &#39; -f 1 | nl)&#34;
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">sudo mkdir -p $PREFIX/opt/shell-color-scripts/colorscripts <span style="color:#f92672">||</span> <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">1</span>
sudo cp -rf colorscripts/* $PREFIX/opt/shell-color-scripts/colorscripts
sudo cp colorscript.sh $PREFIX/bin/colorscript
</code></pre></div>
</div>
</div><div id="footer" class="mb-5">
<hr>
<div class="container text-center">
<a href="https://sqrtminusone.xyz/"><small>Pavel Korytov, 2021</small></a>
</div>
</div>
</body>
</html>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,751 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Guix</title>
<meta name="description" content="Freedom is a state of mind">
<meta name="author" content='SqrtMinusOne'>
<link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
</head>
<body><div class="container mt-5">
<nav class="navbar navbar-expand-sm flex-column flex-sm-row text-nowrap p-0">
<a class="navbar-brand mx-0 mr-sm-auto" href="https://sqrtminusone.xyz/">
SqrtMinusOne
</a>
<div class="navbar-nav flex-row flex-wrap justify-content-center">
<a class="nav-item nav-link" href="/">
Index
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/posts/">
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>
</nav>
</div>
<hr>
<div id="content">
<div class="container">
<p><a href="https://guix.gnu.org/">GNU Guix</a> is (1) a transactional package manager and (2) a GNU/Linux distribution.</p>
<p>My personal selling points are declarative package configuration and transactional upgrades.</p>
<p>References:</p>
<ul>
<li><a href="https://guix.gnu.org/en/help/">Official help</a></li>
<li><a href="https://wiki.systemcrafters.cc/guix">System Crafters wiki</a></li>
<li><a href="https://gitlab.com/pjotrp/guix-notes">Pjotr Prins' Guix notes</a></li>
<li><a href="https://www.youtube.com/watch?v=iBaqOK75cho&amp;list=PLEoMzSkcN8oNxnj7jm5V2ZcGc52002pQU">Davil Wilson&rsquo;s YouTube series</a></li>
</ul>
<div class="ox-hugo-toc toc">
<div></div>
<div class="heading">Table of Contents</div>
<ul>
<li><a href="#contents">Contents</a></li>
<li><a href="#profiles">Profiles</a>
<ul>
<li><a href="#activate-profiles">Activate profiles</a></li>
<li><a href="#update-profiles">Update profiles</a></li>
</ul>
</li>
<li><a href="#channels">Channels</a></li>
<li><a href="#systems">Systems</a>
<ul>
<li><a href="#base-configuration">Base configuration</a></li>
<li><a href="#indigo">indigo</a></li>
<li><a href="#eminence">eminence</a></li>
<li><a href="#azure">azure</a></li>
</ul>
</li>
<li><a href="#system-installation">System installation</a>
<ul>
<li><a href="#preparation">Preparation</a></li>
<li><a href="#installation">Installation</a></li>
<li><a href="#after-installation">After installation</a></li>
</ul>
</li>
<li><a href="#misc-software-and-notes">Misc software &amp; notes</a>
<ul>
<li><a href="#vpn">VPN</a>
<ul>
<li><a href="#vpn-start">vpn-start</a></li>
<li><a href="#vpn-stop">vpn-stop</a></li>
</ul>
</li>
<li><a href="#flatpak">flatpak</a></li>
<li><a href="#conda">conda</a></li>
<li><a href="#slack">Slack</a></li>
<li><a href="#virt-manager">virt-manager</a></li>
<li><a href="#wakatime-cli">wakatime-cli</a></li>
<li><a href="#manifest">Manifest</a></li>
</ul>
</li>
</ul>
</div>
<!--endtoc-->
<h2 id="contents">Contents</h2>
<ul>
<li><a href="#contents">Contents</a></li>
<li><a href="#profiles">Profiles</a>
<ul>
<li><a href="#activate-profiles">Activate profiles</a></li>
<li><a href="#update-profiles">Update profiles</a></li>
</ul>
</li>
<li><a href="#channels">Channels</a></li>
<li><a href="#systems">Systems</a>
<ul>
<li><a href="#base-configuration">Base configuration</a></li>
<li><a href="#indigo">indigo</a></li>
<li><a href="#eminence">eminence</a></li>
<li><a href="#azure">azure</a></li>
</ul>
</li>
<li><a href="#system-installation">System installation</a>
<ul>
<li><a href="#preparation">Preparation</a></li>
<li><a href="#installation">Installation</a></li>
<li><a href="#after-installation">After installation</a></li>
</ul>
</li>
<li><a href="#misc-software-and-notes">Misc software &amp; notes</a>
<ul>
<li><a href="#vpn">VPN</a>
<ul>
<li><a href="#vpn-start">vpn-start</a></li>
<li><a href="#vpn-stop">vpn-stop</a></li>
</ul>
</li>
<li><a href="#flatpak">flatpak</a></li>
<li><a href="#conda">conda</a></li>
<li><a href="#slack">Slack</a></li>
<li><a href="#virt-manager">virt-manager</a></li>
<li><a href="#wakatime-cli">wakatime-cli</a></li>
<li><a href="#manifest">Manifest</a></li>
</ul>
</li>
</ul>
<h2 id="profiles">Profiles</h2>
<p>A profile is a way to group Guix packages. Amongst its advantages, profiles can be defined by manifests, which in turn can be stored in VCS.</p>
<p>References:</p>
<ul>
<li><a href="https://guix.gnu.org/en/cookbook/en/html%5Fnode/Guix-Profiles-in-Practice.html">Guix Profiles in Practice</a></li>
</ul>
<h3 id="activate-profiles">Activate profiles</h3>
<p>A script to activate guix profiles. Usage:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">activate-profiles [profile1] [profile2] ...
</code></pre></div><p>Source: <a href="https://github.com/daviwil/dotfiles/blob/master/Systems.org#activating-profiles">David Wilson&rsquo;s config</a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">GREEN<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;\033[1;32m&#39;</span>
RED<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;\033[1;30m&#39;</span>
NC<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;\033[0m&#39;</span>
GUIX_EXTRA_PROFILES<span style="color:#f92672">=</span>$HOME/.guix-extra-profiles
profiles<span style="color:#f92672">=</span>$*
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> $# -eq <span style="color:#ae81ff">0</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
profiles<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/.config/guix/manifests/*.scm&#34;</span>;
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">for</span> profile in $profiles; <span style="color:#66d9ef">do</span>
<span style="color:#75715e"># Remove the path and file extension, if any</span>
profileName<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>basename $profile<span style="color:#66d9ef">)</span>
profileName<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>profileName%.*<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
profilePath<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$GUIX_EXTRA_PROFILES<span style="color:#e6db74">/</span>$profileName<span style="color:#e6db74">&#34;</span>
manifestPath<span style="color:#f92672">=</span>$HOME/.config/guix/manifests/$profileName.scm
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -f $manifestPath <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
echo
echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>GREEN<span style="color:#e6db74">}</span><span style="color:#e6db74">Activating profile:&#34;</span> $manifestPath <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
echo
mkdir -p $profilePath
guix package --manifest<span style="color:#f92672">=</span>$manifestPath --profile<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$profilePath<span style="color:#e6db74">/</span>$profileName<span style="color:#e6db74">&#34;</span>
<span style="color:#75715e"># Source the new profile</span>
GUIX_PROFILE<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$profilePath<span style="color:#e6db74">/</span>$profileName<span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -f $GUIX_PROFILE/etc/profile <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
. <span style="color:#e6db74">&#34;</span>$GUIX_PROFILE<span style="color:#e6db74">&#34;</span>/etc/profile
<span style="color:#66d9ef">else</span>
echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>RED<span style="color:#e6db74">}</span><span style="color:#e6db74">Couldn&#39;t find profile:&#34;</span> $GUIX_PROFILE/etc/profile <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">else</span>
echo <span style="color:#e6db74">&#34;No profile found at path&#34;</span> $profilePath
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">done</span>
</code></pre></div><h3 id="update-profiles">Update profiles</h3>
<p>A script to update Guix profiles. Usage:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">update-profiles [profile1] [profile2] ...
</code></pre></div><p>Source: once again, <a href="https://github.com/daviwil/dotfiles/blob/master/Systems.org#updating-profiles">David Wilson&rsquo;s config</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">GREEN<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;\033[1;32m&#39;</span>
NC<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;\033[0m&#39;</span>
GUIX_EXTRA_PROFILES<span style="color:#f92672">=</span>$HOME/.guix-extra-profiles
profiles<span style="color:#f92672">=</span>$*
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> $# -eq <span style="color:#ae81ff">0</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
profiles<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$GUIX_EXTRA_PROFILES<span style="color:#e6db74">/*&#34;</span>;
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">for</span> profile in $profiles; <span style="color:#66d9ef">do</span>
profileName<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>basename $profile<span style="color:#66d9ef">)</span>
profilePath<span style="color:#f92672">=</span>$GUIX_EXTRA_PROFILES/$profileName
echo
echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>GREEN<span style="color:#e6db74">}</span><span style="color:#e6db74">Updating profile:&#34;</span> $profilePath <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
echo
guix package --profile<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$profilePath<span style="color:#e6db74">/</span>$profileName<span style="color:#e6db74">&#34;</span> --manifest<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/.config/guix/manifests/</span>$profileName<span style="color:#e6db74">.scm&#34;</span>
<span style="color:#66d9ef">done</span>
</code></pre></div><h2 id="channels">Channels</h2>
<p>Specifying additional channels.</p>
<p><a href="https://github.com/SqrtMinusOne/channel-q">channel-q</a> is my Guix channel. Don&rsquo;t use it at home.</p>
<p>References:</p>
<ul>
<li><a href="https://gitlab.com/nonguix/nonguix">nonguix channel repo</a></li>
<li><a href="https://guix.gnu.org/manual/en/html%5Fnode/Channels.html">Guix channels reference</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#a6e22e">cons*</span>
(<span style="color:#a6e22e">channel</span>
(<span style="color:#a6e22e">name</span> <span style="color:#e6db74">&#39;channel-q</span>)
(<span style="color:#a6e22e">url</span> <span style="color:#e6db74">&#34;file:///home/pavel/Code/channel-q&#34;</span>))
(<span style="color:#a6e22e">channel</span>
(<span style="color:#a6e22e">name</span> <span style="color:#e6db74">&#39;flat</span>)
(<span style="color:#a6e22e">url</span> <span style="color:#e6db74">&#34;https://github.com/flatwhatson/guix-channel.git&#34;</span>)
(<span style="color:#a6e22e">introduction</span>
(<span style="color:#a6e22e">make-channel-introduction</span>
<span style="color:#e6db74">&#34;33f86a4b48205c0dc19d7c036c85393f0766f806&#34;</span>
(<span style="color:#a6e22e">openpgp-fingerprint</span>
<span style="color:#e6db74">&#34;736A C00E 1254 378B A982 7AF6 9DBE 8265 81B6 4490&#34;</span>))))
(<span style="color:#a6e22e">channel</span>
(<span style="color:#a6e22e">name</span> <span style="color:#e6db74">&#39;nonguix</span>)
(<span style="color:#a6e22e">url</span> <span style="color:#e6db74">&#34;https://gitlab.com/nonguix/nonguix&#34;</span>)
<span style="color:#75715e">;; (commit &#34;d54973e47b89fe5772a5b6e2d0c0b86acb089e27&#34;)</span>
(<span style="color:#a6e22e">introduction</span>
(<span style="color:#a6e22e">make-channel-introduction</span>
<span style="color:#e6db74">&#34;897c1a470da759236cc11798f4e0a5f7d4d59fbc&#34;</span>
(<span style="color:#a6e22e">openpgp-fingerprint</span>
<span style="color:#e6db74">&#34;2A39 3FFF 68F4 EF7A 3D29 12AF 6F51 20A0 22FB B2D5&#34;</span>))))
%default-channels)
</code></pre></div><h2 id="systems">Systems</h2>
<p>Configuring systems with Guix.</p>
<p>Yes, all my machines are named after colors I like.</p>
<h3 id="base-configuration">Base configuration</h3>
<p>The base configuration is shared between all the machines.</p>
<p>While it&rsquo;s possible to make a single <code>.scm</code> file with base configuration and load it, I noticed that it produces more cryptic error messages whenever there is an error in the base file, so I opt-in for noweb.</p>
<p><code>guix system</code> invocation is as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">sudo -E guix system reconfigure ~/.config/guix/systems/[system].scm
</code></pre></div><p>Common modules:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span>))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> system nss))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages bash))
(<span style="color:#a6e22e">use-modules</span> ((<span style="color:#a6e22e">gnu</span> packages base) <span style="color:#f92672">#</span>:select (<span style="color:#a6e22e">coreutils</span> glibc)))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages certs))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages version-control))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages vim))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages gnome))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages xorg))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages wm))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages openbox))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> services docker))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> services cups))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> services virtualization))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">srfi</span> srfi-1))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">guix</span> channels))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">guix</span> inferior))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">nongnu</span> packages linux))
(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">nongnu</span> system linux-initrd))
(<span style="color:#a6e22e">use-service-modules</span> desktop networking ssh xorg nix)
(<span style="color:#a6e22e">use-package-modules</span> ssh)
</code></pre></div><p>In principle, we could define a variable called <code>base-operating-system</code> and extend it in ancestors. However, then we would have to define mandatory fields like <code>host-name</code>, <code>bootloader</code> with dummy values. Since I&rsquo;m already using noweb, there is little point.</p>
<p>The following code will be inserted at the top of the <code>operating-system</code> definition.</p>
<p>Use the full Linux kernel. I hope I&rsquo;ll be able to use Libre kernel somewhere later.</p>
<p>Inferior in the kernel is used to avoid recompilation. It looks like I can pin these to different commits than in my <code>channels.scm</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#a6e22e">kernel</span>
(<span style="color:#a6e22e">let*</span>
((<span style="color:#a6e22e">channels</span>
(list (<span style="color:#a6e22e">channel</span>
(<span style="color:#a6e22e">name</span> <span style="color:#e6db74">&#39;nonguix</span>)
(<span style="color:#a6e22e">url</span> <span style="color:#e6db74">&#34;https://gitlab.com/nonguix/nonguix&#34;</span>)
(<span style="color:#a6e22e">commit</span> <span style="color:#e6db74">&#34;d3c5eea0cbfe3e5bfbcf1fe15bc916fefacc624f&#34;</span>))
(<span style="color:#a6e22e">channel</span>
(<span style="color:#a6e22e">name</span> <span style="color:#e6db74">&#39;guix</span>)
(<span style="color:#a6e22e">url</span> <span style="color:#e6db74">&#34;https://git.savannah.gnu.org/git/guix.git&#34;</span>)
(<span style="color:#a6e22e">commit</span> <span style="color:#e6db74">&#34;cf88c967afbf15c58efb0ba37d6638f1be9a0481&#34;</span>))))
(<span style="color:#a6e22e">inferior</span>
(<span style="color:#a6e22e">inferior-for-channels</span> channels)))
(<span style="color:#a6e22e">first</span> (<span style="color:#a6e22e">lookup-inferior-packages</span> inferior <span style="color:#e6db74">&#34;linux&#34;</span> <span style="color:#e6db74">&#34;5.12.9&#34;</span>))))
<span style="color:#75715e">;; (kernel linux)</span>
(<span style="color:#a6e22e">initrd</span> microcode-initrd)
(<span style="color:#a6e22e">firmware</span> (list linux-firmware))
(<span style="color:#a6e22e">locale</span> <span style="color:#e6db74">&#34;en_US.utf8&#34;</span>)
(<span style="color:#a6e22e">timezone</span> <span style="color:#e6db74">&#34;Europe/Moscow&#34;</span>)
</code></pre></div><p>US/RU keyboard layout, switch with Alt+Shift.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#a6e22e">keyboard-layout</span> (<span style="color:#a6e22e">keyboard-layout</span> <span style="color:#e6db74">&#34;us,ru&#34;</span> <span style="color:#f92672">#</span>:options <span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;grp:alt_shift_toggle&#34;</span>)))
</code></pre></div><p>User accounts.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#a6e22e">users</span> (<span style="color:#a6e22e">cons*</span> (<span style="color:#a6e22e">user-account</span>
(<span style="color:#a6e22e">name</span> <span style="color:#e6db74">&#34;pavel&#34;</span>)
(<span style="color:#a6e22e">comment</span> <span style="color:#e6db74">&#34;Pavel&#34;</span>)
(<span style="color:#a6e22e">group</span> <span style="color:#e6db74">&#34;users&#34;</span>)
(<span style="color:#a6e22e">home-directory</span> <span style="color:#e6db74">&#34;/home/pavel&#34;</span>)
(<span style="color:#a6e22e">supplementary-groups</span>
<span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;wheel&#34;</span> <span style="color:#75715e">;; sudo</span>
<span style="color:#e6db74">&#34;netdev&#34;</span> <span style="color:#75715e">;; network devices</span>
<span style="color:#e6db74">&#34;audio&#34;</span>
<span style="color:#e6db74">&#34;video&#34;</span>
<span style="color:#e6db74">&#34;input&#34;</span>
<span style="color:#e6db74">&#34;tty&#34;</span>
<span style="color:#e6db74">&#34;docker&#34;</span>
<span style="color:#e6db74">&#34;scanner&#34;</span>
<span style="color:#e6db74">&#34;libvirt&#34;</span>
<span style="color:#e6db74">&#34;lp&#34;</span>)))
%base-user-accounts))
</code></pre></div><p>Base packages, necessary right after the installation.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#a6e22e">packages</span>
(<span style="color:#a6e22e">append</span>
(list nss-certs
git
i3-gaps
i3lock
openbox
xterm
vim)
%base-packages))
</code></pre></div><p>Default services for each machine:</p>
<ul>
<li>override the default <code>%desktop-services</code> to add OpenVPN support</li>
<li>add nix service</li>
<li>add docker service</li>
<li>add CUPS service</li>
<li>add libvirt service</li>
<li>add a symlink to ELF interpreter to where most Linux binaries expect it</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#66d9ef">define </span>%my-base-services
(<span style="color:#a6e22e">cons*</span>
(<span style="color:#a6e22e">service</span> openssh-service-type)
(<span style="color:#a6e22e">screen-locker-service</span> i3lock <span style="color:#e6db74">&#34;i3lock&#34;</span>)
(<span style="color:#a6e22e">extra-special-file</span> <span style="color:#e6db74">&#34;/lib64/ld-linux-x86-64.so.2&#34;</span> (<span style="color:#a6e22e">file-append</span> glibc <span style="color:#e6db74">&#34;/lib/ld-linux-x86-64.so.2&#34;</span>))
(<span style="color:#a6e22e">service</span> nix-service-type)
(<span style="color:#a6e22e">service</span> cups-service-type
(<span style="color:#a6e22e">cups-configuration</span>
(<span style="color:#a6e22e">web-interface?</span> <span style="color:#66d9ef">#t</span>)))
(<span style="color:#a6e22e">service</span> docker-service-type)
(<span style="color:#a6e22e">service</span> libvirt-service-type
(<span style="color:#a6e22e">libvirt-configuration</span>
(<span style="color:#a6e22e">unix-sock-group</span> <span style="color:#e6db74">&#34;libvirt&#34;</span>)
(<span style="color:#a6e22e">tls-port</span> <span style="color:#e6db74">&#34;16555&#34;</span>)))
(<span style="color:#a6e22e">service</span> virtlog-service-type)
(<span style="color:#a6e22e">modify-services</span> %desktop-services
(<span style="color:#a6e22e">network-manager-service-type</span>
config =&gt;
(<span style="color:#a6e22e">network-manager-configuration</span>
(<span style="color:#a6e22e">inherit</span> config)
(<span style="color:#a6e22e">vpn-plugins</span> (list network-manager-openvpn)))))))
</code></pre></div><h3 id="indigo">indigo</h3>
<p><code>indigo</code> is my desktop PC.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">&lt;&lt;system-common&gt;&gt;
(<span style="color:#a6e22e">operating-system</span>
&lt;&lt;system-base&gt;&gt;
(<span style="color:#a6e22e">host-name</span> <span style="color:#e6db74">&#34;indigo&#34;</span>)
(<span style="color:#a6e22e">services</span> (<span style="color:#a6e22e">cons*</span>
(<span style="color:#a6e22e">set-xorg-configuration</span>
(<span style="color:#a6e22e">xorg-configuration</span>
(<span style="color:#a6e22e">keyboard-layout</span> keyboard-layout)))
%my-base-services))
(<span style="color:#a6e22e">bootloader</span>
(<span style="color:#a6e22e">bootloader-configuration</span>
(<span style="color:#a6e22e">bootloader</span> grub-efi-bootloader)
(<span style="color:#a6e22e">target</span> <span style="color:#e6db74">&#34;/boot/efi&#34;</span>)
(<span style="color:#a6e22e">keyboard-layout</span> keyboard-layout)))
(<span style="color:#a6e22e">swap-devices</span>
(list (<span style="color:#a6e22e">uuid</span> <span style="color:#e6db74">&#34;059a2c26-8f70-4986-adf0-1a2e7b511404&#34;</span>)))
(<span style="color:#a6e22e">file-systems</span>
(<span style="color:#a6e22e">cons*</span> (<span style="color:#a6e22e">file-system</span>
(<span style="color:#a6e22e">mount-point</span> <span style="color:#e6db74">&#34;/&#34;</span>)
(<span style="color:#a6e22e">device</span> (<span style="color:#a6e22e">file-system-label</span> <span style="color:#e6db74">&#34;my-root&#34;</span>))
(<span style="color:#a6e22e">type</span> <span style="color:#e6db74">&#34;ext4&#34;</span>))
(<span style="color:#a6e22e">file-system</span>
(<span style="color:#a6e22e">mount-point</span> <span style="color:#e6db74">&#34;/boot/efi&#34;</span>)
(<span style="color:#a6e22e">device</span> <span style="color:#e6db74">&#34;/dev/sda1&#34;</span>)
(<span style="color:#a6e22e">type</span> <span style="color:#e6db74">&#34;vfat&#34;</span>))
%base-file-systems)))
</code></pre></div><h3 id="eminence">eminence</h3>
<p><code>eminence</code> is a HP 15s laptop.</p>
<p><code>%backlight-udev-rule</code> should enable members of <code>video</code> group change the display backlight. See the relevant page at <a href="https://wiki.archlinux.org/title/Backlight">Arch Wiki</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">&lt;&lt;system-common&gt;&gt;
(<span style="color:#66d9ef">define </span>%backlight-udev-rule
(<span style="color:#a6e22e">udev-rule</span>
<span style="color:#e6db74">&#34;90-backlight.rules&#34;</span>
(string-append <span style="color:#e6db74">&#34;ACTION==\&#34;add\&#34;, SUBSYSTEM==\&#34;backlight\&#34;, &#34;</span>
<span style="color:#e6db74">&#34;RUN+=\&#34;/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\&#34;&#34;</span>
<span style="color:#e6db74">&#34;\n&#34;</span>
<span style="color:#e6db74">&#34;ACTION==\&#34;add\&#34;, SUBSYSTEM==\&#34;backlight\&#34;, &#34;</span>
<span style="color:#e6db74">&#34;RUN+=\&#34;/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\&#34;&#34;</span>)))
(<span style="color:#a6e22e">operating-system</span>
&lt;&lt;system-base&gt;&gt;
(<span style="color:#a6e22e">host-name</span> <span style="color:#e6db74">&#34;eminence&#34;</span>)
(<span style="color:#a6e22e">services</span> (<span style="color:#a6e22e">cons*</span>
(<span style="color:#a6e22e">set-xorg-configuration</span>
(<span style="color:#a6e22e">xorg-configuration</span>
(<span style="color:#a6e22e">keyboard-layout</span> keyboard-layout)))
(<span style="color:#a6e22e">modify-services</span> %my-base-services
(<span style="color:#a6e22e">elogind-service-type</span>
config =&gt;
(<span style="color:#a6e22e">elogind-configuration</span>
(<span style="color:#a6e22e">inherit</span> config)
(<span style="color:#a6e22e">handle-lid-switch-external-power</span> <span style="color:#e6db74">&#39;suspend</span>)))
(<span style="color:#a6e22e">udev-service-type</span>
config =&gt;
(<span style="color:#a6e22e">udev-configuration</span>
(<span style="color:#a6e22e">inherit</span> config)
(<span style="color:#a6e22e">rules</span> (cons %backlight-udev-rule
(<span style="color:#a6e22e">udev-configuration-rules</span> config))))))))
(<span style="color:#a6e22e">bootloader</span>
(<span style="color:#a6e22e">bootloader-configuration</span>
(<span style="color:#a6e22e">bootloader</span> grub-efi-bootloader)
(<span style="color:#a6e22e">target</span> <span style="color:#e6db74">&#34;/boot/efi&#34;</span>)
(<span style="color:#a6e22e">keyboard-layout</span> keyboard-layout)))
(<span style="color:#a6e22e">swap-devices</span>
(list (<span style="color:#a6e22e">uuid</span> <span style="color:#e6db74">&#34;f93cf3f6-7ee7-42ec-8ee2-f3d896fdf9b5&#34;</span>)))
(<span style="color:#a6e22e">file-systems</span>
(<span style="color:#a6e22e">cons*</span> (<span style="color:#a6e22e">file-system</span>
(<span style="color:#a6e22e">mount-point</span> <span style="color:#e6db74">&#34;/&#34;</span>)
(<span style="color:#a6e22e">device</span>
(<span style="color:#a6e22e">uuid</span> <span style="color:#e6db74">&#34;1d937704-bbeb-43b5-bc63-453886c426af&#34;</span>
<span style="color:#e6db74">&#39;ext4</span>))
(<span style="color:#a6e22e">type</span> <span style="color:#e6db74">&#34;ext4&#34;</span>))
(<span style="color:#a6e22e">file-system</span>
(<span style="color:#a6e22e">mount-point</span> <span style="color:#e6db74">&#34;/boot/efi&#34;</span>)
(<span style="color:#a6e22e">device</span> (<span style="color:#a6e22e">uuid</span> <span style="color:#e6db74">&#34;0031-3784&#34;</span> <span style="color:#e6db74">&#39;fat32</span>))
(<span style="color:#a6e22e">type</span> <span style="color:#e6db74">&#34;vfat&#34;</span>))
%base-file-systems)))
</code></pre></div><h3 id="azure">azure</h3>
<p><code>azure</code> is a Lenovo Ideapad 330 laptop.</p>
<p><code>%backlight-udev-rule</code> should enable members of <code>video</code> group change the display backlight. See the relevant page at <a href="https://wiki.archlinux.org/title/Backlight">Arch Wiki</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">&lt;&lt;system-common&gt;&gt;
(<span style="color:#66d9ef">define </span>%backlight-udev-rule
(<span style="color:#a6e22e">udev-rule</span>
<span style="color:#e6db74">&#34;90-backlight.rules&#34;</span>
(string-append <span style="color:#e6db74">&#34;ACTION==\&#34;add\&#34;, SUBSYSTEM==\&#34;backlight\&#34;, &#34;</span>
<span style="color:#e6db74">&#34;RUN+=\&#34;/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\&#34;&#34;</span>
<span style="color:#e6db74">&#34;\n&#34;</span>
<span style="color:#e6db74">&#34;ACTION==\&#34;add\&#34;, SUBSYSTEM==\&#34;backlight\&#34;, &#34;</span>
<span style="color:#e6db74">&#34;RUN+=\&#34;/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\&#34;&#34;</span>)))
(<span style="color:#a6e22e">operating-system</span>
&lt;&lt;system-base&gt;&gt;
(<span style="color:#a6e22e">host-name</span> <span style="color:#e6db74">&#34;azure&#34;</span>)
(<span style="color:#a6e22e">services</span> (<span style="color:#a6e22e">cons*</span>
(<span style="color:#a6e22e">set-xorg-configuration</span>
(<span style="color:#a6e22e">xorg-configuration</span>
(<span style="color:#a6e22e">keyboard-layout</span> keyboard-layout)))
(<span style="color:#a6e22e">modify-services</span> %my-base-services
(<span style="color:#a6e22e">elogind-service-type</span> config =&gt;
(<span style="color:#a6e22e">elogind-configuration</span> (<span style="color:#a6e22e">inherit</span> config)
(<span style="color:#a6e22e">handle-lid-switch-external-power</span> <span style="color:#e6db74">&#39;suspend</span>)))
(<span style="color:#a6e22e">udev-service-type</span> config =&gt;
(<span style="color:#a6e22e">udev-configuration</span> (<span style="color:#a6e22e">inherit</span> config)
(<span style="color:#a6e22e">rules</span> (cons %backlight-udev-rule
(<span style="color:#a6e22e">udev-configuration-rules</span> config))))))))
(<span style="color:#a6e22e">bootloader</span>
(<span style="color:#a6e22e">bootloader-configuration</span>
(<span style="color:#a6e22e">bootloader</span> grub-efi-bootloader)
(<span style="color:#a6e22e">target</span> <span style="color:#e6db74">&#34;/boot/efi&#34;</span>)
(<span style="color:#a6e22e">keyboard-layout</span> keyboard-layout)))
(<span style="color:#a6e22e">swap-devices</span>
(list (<span style="color:#a6e22e">uuid</span> <span style="color:#e6db74">&#34;4b2dedb3-b111-4e69-8c05-6daa2b072c76&#34;</span>)))
(<span style="color:#a6e22e">file-systems</span>
(<span style="color:#a6e22e">cons*</span> (<span style="color:#a6e22e">file-system</span>
(<span style="color:#a6e22e">mount-point</span> <span style="color:#e6db74">&#34;/&#34;</span>)
(<span style="color:#a6e22e">device</span> (<span style="color:#a6e22e">file-system-label</span> <span style="color:#e6db74">&#34;my-root&#34;</span>))
(<span style="color:#a6e22e">type</span> <span style="color:#e6db74">&#34;ext4&#34;</span>))
(<span style="color:#a6e22e">file-system</span>
(<span style="color:#a6e22e">mount-point</span> <span style="color:#e6db74">&#34;/boot/efi&#34;</span>)
(<span style="color:#a6e22e">device</span> <span style="color:#e6db74">&#34;/dev/sda1&#34;</span>)
(<span style="color:#a6e22e">type</span> <span style="color:#e6db74">&#34;vfat&#34;</span>))
%base-file-systems)))
</code></pre></div><h2 id="system-installation">System installation</h2>
<h3 id="preparation">Preparation</h3>
<p>In my case, the provided ISO doesn&rsquo;t work because of the Libre kernel.</p>
<p>Fortunately, David Wilson has made <a href="https://github.com/SystemCrafters/guix-installer">a repository</a> with a toolchain to make an ISO with the full kernel. In case it won&rsquo;t be an option, the <a href="https://gitlab.com/nonguix/nonguix">nonguix repo</a> also has instructions on how to do that.</p>
<p>When an ISO is there, we have to write it on a USB stick. Run <code>sudo fdisk -l</code> to get a list of disks.</p>
<p>The approach in the official instruction is to create a bootable USB with <code>dd</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">sudo dd of=/dev/sdxX if=&lt;path-to-iso&gt; status=progress &amp;&amp; sync
</code></pre></div><p>However, I couldn&rsquo;t make it work for some strange reason. Fortunately, <code>gnome-disk-utility</code> was able to produce a bootable USB.</p>
<h3 id="installation">Installation</h3>
<p>Going further, the official instructions for installation &amp; SystemCrafters wiki entry are pretty good, so it&rsquo;s not necessary to repeat them here.</p>
<h3 id="after-installation">After installation</h3>
<p>After the installation, the strategy is as follows.</p>
<p>Set a password for the main user (pavel). Login with openbox to get a tolerable interface because the i3 default config is horrible.</p>
<p><a href="https://guix.gnu.org/en/manual/en/html%5Fnode/Keyboard-Layout-and-Networking-and-Partitioning.html#Keyboard-Layout-and-Networking-and-Partitioning">Connect to the internet</a>.</p>
<p>Clone the dotfiles repo:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">mkdir Code
cd Code
git clone https://github.com/SqrtMinusOne/dotfiles.git
</code></pre></div><p>Copy the channels file and run guix pull:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">cp ~/Code/dotfiles/.config/guix/channels.scm ~/.config/guix
guix pull
</code></pre></div><p>The first pull usually takes a while. After that install yadm and pull dotfiles:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">guix install yadm
guix clone https://github.com/SqrtMinusOne/dotfiles.git
</code></pre></div><p>And activate the required profiles. Again, downloading &amp; building Emacs, Starship and stuff will take a while.</p>
<p>Don&rsquo;t forget to install <code>JetBrainsMono Nerd Font</code>.</p>
<h2 id="misc-software-and-notes">Misc software &amp; notes</h2>
<table>
<thead>
<tr>
<th>Category</th>
<th>Guix dependency</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>system</td>
<td>patchelf</td>
<td>A program to modify existsing ELF executables</td>
</tr>
<tr>
<td>system</td>
<td>glibc</td>
<td>A lot of stuff, including ELF interpeter and <code>ldd</code></td>
</tr>
</tbody>
</table>
<h3 id="vpn">VPN</h3>
<table>
<thead>
<tr>
<th>Category</th>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>system</td>
<td>openvpn</td>
</tr>
<tr>
<td>system</td>
<td>openvpn-update-resolve-conf</td>
</tr>
</tbody>
</table>
<p>I&rsquo;m not sure how to properly spin up VPN on Guix, so here is what I&rsquo;m doing now, after some trial and error.</p>
<p>I&rsquo;m currently using CyberGhost VPN. <code>~/.vpn</code> folder stores its OpenVPN config (<code>openvpn.ovpn</code>), modified as follows:</p>
<ul>
<li>
<p>paths to <code>ca</code>, <code>cert</code> and <code>key</code> are made absolute</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"><span style="color:#a6e22e">ca</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.vpn/</span><span style="color:#a6e22e">ca</span>.<span style="color:#a6e22e">crt</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">cert</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.vpn/</span><span style="color:#a6e22e">client</span>.<span style="color:#a6e22e">crt</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">key</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.vpn/</span><span style="color:#a6e22e">client</span>.<span style="color:#a6e22e">key</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div></li>
<li>
<p>added <code>auth-user-pass</code> with a link to login info</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"><span style="color:#a6e22e">auth</span>-<span style="color:#a6e22e">user</span>-<span style="color:#a6e22e">pass</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.vpn/</span><span style="color:#a6e22e">auth</span>.<span style="color:#a6e22e">conf</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div><p><code>auth.conf</code> looks like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">login
password
</code></pre></div></li>
<li>
<p>run <a href="https://github.com/alfredopalhares/openvpn-update-resolv-conf">openvpn-update-resolv-conf</a> script to fix DNS. <code>openvpn-update-resolve-conf</code> originates in my <a href="https://github.com/SqrtMinusOne/channel-q">channel-q</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"><span style="color:#a6e22e">setenv</span> <span style="color:#a6e22e">PATH</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.guix-extra-profiles/</span><span style="color:#a6e22e">system</span><span style="color:#e6db74">/system/</span><span style="color:#a6e22e">bin</span>:<span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.guix-extra-profiles/</span><span style="color:#a6e22e">system</span><span style="color:#e6db74">/system/</span><span style="color:#a6e22e">sbin</span>:<span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.guix-extra-profiles/</span><span style="color:#a6e22e">console</span><span style="color:#e6db74">/console/</span><span style="color:#a6e22e">bin</span>:<span style="color:#e6db74">/run/</span><span style="color:#a6e22e">current</span>-<span style="color:#a6e22e">system</span><span style="color:#e6db74">/profile/</span><span style="color:#a6e22e">bin</span>:<span style="color:#e6db74">/run/</span><span style="color:#a6e22e">current</span>-<span style="color:#a6e22e">system</span><span style="color:#e6db74">/profile/</span><span style="color:#a6e22e">sbin</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">up</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.guix-extra-profiles/</span><span style="color:#a6e22e">system</span><span style="color:#e6db74">/system/</span><span style="color:#a6e22e">bin</span>/<span style="color:#a6e22e">update</span>-<span style="color:#a6e22e">resolv</span>-<span style="color:#a6e22e">conf</span>.<span style="color:#a6e22e">sh</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">down</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.guix-extra-profiles/</span><span style="color:#a6e22e">system</span><span style="color:#e6db74">/system/</span><span style="color:#a6e22e">bin</span>/<span style="color:#a6e22e">update</span>-<span style="color:#a6e22e">resolv</span>-<span style="color:#a6e22e">conf</span>.<span style="color:#a6e22e">sh</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div><p><code>setenv PATH</code> is necessary because both <code>resolvconf</code> (openresolve) and <code>update-resolv-conf.sh</code> are shell scripts which need GNU coreutils and stuff, and OpenVPN clears PATH by default.</p>
</li>
<li>
<p>run a script to fix Docker routes</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"><span style="color:#a6e22e">route</span>-<span style="color:#a6e22e">up</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/bin/</span><span style="color:#a6e22e">scripts</span>/<span style="color:#a6e22e">vpn</span>-<span style="color:#a6e22e">fix</span>-<span style="color:#a6e22e">routes</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div><p>References:</p>
<ul>
<li><a href="https://github.com/moby/libnetwork/issues/779">Github issue</a></li>
</ul>
<p>The script itself:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">echo <span style="color:#e6db74">&#34;Adding default route to </span>$route_vpn_gateway<span style="color:#e6db74"> with /0 mask...&#34;</span>
IP<span style="color:#f92672">=</span>/run/current-system/profile/sbin/ip
$IP route add default via $route_vpn_gateway
echo <span style="color:#e6db74">&#34;Removing /1 routes...&#34;</span>
$IP route del 0.0.0.0/1 via $route_vpn_gateway
$IP route del 128.0.0.0/1 via $route_vpn_gateway
</code></pre></div></li>
</ul>
<h4 id="vpn-start">vpn-start</h4>
<p>As of now, CyberGhost doesn&rsquo;t provide ipv6, so we have to disable it.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">export DISPLAY<span style="color:#f92672">=</span>:0
CONN<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>nmcli -f NAME con show --active | grep -Ev <span style="color:#e6db74">&#34;(.*docker.*|NAME|br-.*|veth.*|tun.*|vnet.*|virbr.*)&#34;</span> | sed <span style="color:#e6db74">&#39;s/ *$//g&#39;</span><span style="color:#66d9ef">)</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">&#34;</span>$CONN<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
echo <span style="color:#e6db74">&#34;No connection!&#34;</span>
notify-send <span style="color:#e6db74">&#34;VPN&#34;</span> <span style="color:#e6db74">&#34;No connection for VPN to run&#34;</span>
exit
<span style="color:#66d9ef">fi</span>
echo <span style="color:#e6db74">&#34;Connection: </span>$CONN<span style="color:#e6db74">&#34;</span>
notify-send <span style="color:#e6db74">&#34;VPN&#34;</span> <span style="color:#e6db74">&#34;Initializing for connection: </span>$CONN<span style="color:#e6db74">&#34;</span>
pkexec nmcli con modify <span style="color:#e6db74">&#34;</span>$CONN<span style="color:#e6db74">&#34;</span> ipv6.method ignore
nmcli connection up <span style="color:#e6db74">&#34;</span>$CONN<span style="color:#e6db74">&#34;</span>
pkexec openvpn --config ~/.vpn/openvpn.ovpn
</code></pre></div><h4 id="vpn-stop">vpn-stop</h4>
<p>Also a script to reverse the changes.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">CONN<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>nmcli -f NAME con show --active | grep -Ev <span style="color:#e6db74">&#34;(.*docker.*|NAME|br-.*|veth.*|tun.*)&#34;</span> | sed <span style="color:#e6db74">&#39;s/ *$//g&#39;</span><span style="color:#66d9ef">)</span>
echo <span style="color:#e6db74">&#34;Connection: </span>$CONN<span style="color:#e6db74">&#34;</span>
pkexec nmcli con modify <span style="color:#e6db74">&#34;</span>$CONN<span style="color:#e6db74">&#34;</span> ipv6.method auto
nmcli connection up <span style="color:#e6db74">&#34;</span>$CONN<span style="color:#e6db74">&#34;</span>
</code></pre></div><h3 id="flatpak">flatpak</h3>
<p>As for now, the easiest way to install most of proprietary software is via flatpak. See the relevant section in <a href="/configs/desktop/">Desktop.org</a>.</p>
<h3 id="conda">conda</h3>
<p><a href="https://docs.conda.io/en/latest/">conda</a> is a package manager, which I use for managing various versions of Python &amp; Node.js.</p>
<p>It is packaged for GNU Guix, although the definition has its fair share of workarounds. It is almost surprising to see it work with all the C libraries and stuff. But there are still some problems.</p>
<p>First, it&rsquo;s impossible to perform <code>conda init</code> to patch files like <code>.bashrc</code>, because the command is hell-bent on modifying <code>/gnu/store/</code>. So I do this manually, look for the <code>init_conda</code> procedures in <a href="/configs/console/">Console.org</a>.</p>
<p>Second, base environment root is <code>/gnu/store</code>, so don&rsquo;t install anything there.</p>
<p>Third, by default it tries to create envronments in <code>/gnu/store</code>. I think it&rsquo;s enough to create one environment like this to fix it:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">mkdir -p ~/.conda/envs
conda create -p ~/.conda/envs/test
</code></pre></div><p>Finally, I also want to have an ability to use global npm. Some settings for that are located in <a href="Console">Console.org</a>. Here we want to unset <code>NPM_CONFIG_USERCONFIG</code> if there is npm available in the environment.</p>
<p>So here is a script to set up conda hooks:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e"># Get writable conda envs with npm &amp; without</span>
readarray -t CONDA_ENVS_ALL <span style="color:#f92672">&lt;&lt;&lt;</span> <span style="color:#66d9ef">$(</span>conda env list --json | jq <span style="color:#e6db74">&#39;.envs[]&#39;</span><span style="color:#66d9ef">)</span>
CONDA_ENVS_NPM<span style="color:#f92672">=()</span>
CONDA_ENVS_NO_NPM<span style="color:#f92672">=()</span>
<span style="color:#66d9ef">for</span> env in <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>CONDA_ENVS_ALL[@]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>; <span style="color:#66d9ef">do</span>
env<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>env:1:<span style="color:#e6db74">${#</span>env<span style="color:#e6db74">}</span>-2<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -w <span style="color:#e6db74">&#34;</span>$env<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -f <span style="color:#e6db74">&#34;</span>$env<span style="color:#e6db74">/bin/npm&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
CONDA_ENVS_NPM<span style="color:#f92672">+=(</span>$env<span style="color:#f92672">)</span>
<span style="color:#66d9ef">else</span>
CONDA_ENVS_NO_NPM<span style="color:#f92672">+=(</span>$env<span style="color:#f92672">)</span>
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">fi</span>
<span style="color:#66d9ef">done</span>
<span style="color:#66d9ef">for</span> env in <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>CONDA_ENVS_NPM[@]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>; <span style="color:#66d9ef">do</span>
echo <span style="color:#e6db74">&#34;Found npm in </span>$env<span style="color:#e6db74">&#34;</span>
mkdir -p <span style="color:#e6db74">&#34;</span>$env<span style="color:#e6db74">/etc/conda/activate.d&#34;</span>
mkdir -p <span style="color:#e6db74">&#34;</span>$env<span style="color:#e6db74">/etc/conda/deactivate.d&#34;</span>
echo <span style="color:#e6db74">&#34;unset NPM_CONFIG_USERCONFIG&#34;</span> &gt; <span style="color:#e6db74">&#34;</span>$env<span style="color:#e6db74">/etc/conda/activate.d/conda.sh&#34;</span>
echo <span style="color:#e6db74">&#34;set -e NPM_CONFIG_USERCONFIG&#34;</span> &gt; <span style="color:#e6db74">&#34;</span>$env<span style="color:#e6db74">/etc/conda/activate.d/conda.fish&#34;</span>
echo <span style="color:#e6db74">&#34;export NPM_CONFIG_USERCONFIG=</span>$HOME<span style="color:#e6db74">/._npmrc&#34;</span> &gt; <span style="color:#e6db74">&#34;</span>$env<span style="color:#e6db74">/etc/conda/deactivate.d/conda.sh&#34;</span>
echo <span style="color:#e6db74">&#34;export NPM_CONFIG_USERCONFIG=</span>$HOME<span style="color:#e6db74">/._npmrc&#34;</span> &gt; <span style="color:#e6db74">&#34;</span>$env<span style="color:#e6db74">/etc/conda/deactivate.d/conda.fish&#34;</span>
<span style="color:#66d9ef">done</span>
<span style="color:#66d9ef">for</span> env in <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>CONDA_ENVS_NO_NPM<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>; <span style="color:#66d9ef">do</span>
echo <span style="color:#e6db74">&#34;Did not found npm in </span>$env<span style="color:#e6db74">&#34;</span>
rm -rf <span style="color:#e6db74">&#34;</span>$env<span style="color:#e6db74">/etc/conda/activate.d/conda.sh&#34;</span> <span style="color:#f92672">||</span> true
rm -rf <span style="color:#e6db74">&#34;</span>$env<span style="color:#e6db74">/etc/conda/activate.d/conda.fish&#34;</span> <span style="color:#f92672">||</span> true
rm -rf <span style="color:#e6db74">&#34;</span>$env<span style="color:#e6db74">/etc/conda/deactivate.d/conda.sh&#34;</span> <span style="color:#f92672">||</span> true
rm -rf <span style="color:#e6db74">&#34;</span>$env<span style="color:#e6db74">/etc/conda/deactivate.d/conda.fish&#34;</span> <span style="color:#f92672">||</span> true
<span style="color:#66d9ef">done</span>
</code></pre></div><h3 id="slack">Slack</h3>
<p>What a nonsense of a program.</p>
<p>I was able to launch the nix version with the following wrapper script:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">export PATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/bin/dummies:</span>$PATH<span style="color:#e6db74">&#34;</span>
mkdir -p ~/.cache/slack
slack -r ~/.cache/slack
</code></pre></div><p>Also, it requires a <code>lsb_release</code> in the PATH, so here is one:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">echo <span style="color:#e6db74">&#34;LSB Version: Hey. I spent an hour figuring out why Slack doesn&#39;t launch.&#34;</span>
echo <span style="color:#e6db74">&#34;Distributor ID: It seems like it requires an lsb_release.&#34;</span>
echo <span style="color:#e6db74">&#34;Description: But GNU Guix doesn&#39;t have one.&#34;</span>
echo <span style="color:#e6db74">&#34;Release: 42.2&#34;</span>
echo <span style="color:#e6db74">&#34;Codename: n/a&#34;</span>
</code></pre></div><h3 id="virt-manager">virt-manager</h3>
<p>Run the following to fix the network:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">sudo virsh net-define /run/current-system/profile/etc/libvirt/qemu/networks/default.xml
sudo virsh net-start default
sudo herd restart libvirtd
</code></pre></div><h3 id="wakatime-cli">wakatime-cli</h3>
<table>
<thead>
<tr>
<th>Note</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>TODO</td>
<td>Package this for Guix</td>
</tr>
</tbody>
</table>
<p>Before I figure out how to package this for Guix:</p>
<ul>
<li>Clone <a href="https://github.com/wakatime/wakatime-cli">the repo</a></li>
<li>Run <code>go build</code></li>
<li>Copy the binary to the <code>~/bin</code> folder</li>
</ul>
<h3 id="manifest">Manifest</h3>
<p><a id="code-snippet--packages"></a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(my/format-guix-dependencies category)
</code></pre></div><p>System</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#a6e22e">specifications-&gt;manifest</span>
<span style="color:#f92672">&#39;</span>(
&lt;&lt;packages(<span style="color:#e6db74">&#34;system&#34;</span>)&gt;&gt;))
</code></pre></div>
</div>
</div><div id="footer" class="mb-5">
<hr>
<div class="container text-center">
<a href="https://sqrtminusone.xyz/"><small>Pavel Korytov, 2021</small></a>
</div>
</div>
</body>
</html>

89
public/configs/index.html Normal file
View file

@ -0,0 +1,89 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Configs</title>
<meta name="description" content="Freedom is a state of mind">
<meta name="author" content='SqrtMinusOne'>
<link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
<link rel="alternate" type="application/rss+xml" href="https://sqrtminusone.xyz/configs/index.xml" title="SqrtMinusOne" />
</head>
<body><div class="container mt-5">
<nav class="navbar navbar-expand-sm flex-column flex-sm-row text-nowrap p-0">
<a class="navbar-brand mx-0 mr-sm-auto" href="https://sqrtminusone.xyz/">
SqrtMinusOne
</a>
<div class="navbar-nav flex-row flex-wrap justify-content-center">
<a class="nav-item nav-link" href="/">
Index
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/posts/">
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>
</nav>
</div>
<hr>
<div id="content">
<div class="container">
<h1>Configs</h1>
<ul>
<li><a href="https://sqrtminusone.xyz/configs/console/">0001-01-01 | Console</a></li>
<li><a href="https://sqrtminusone.xyz/configs/desktop/">0001-01-01 | Desktop</a></li>
<li><a href="https://sqrtminusone.xyz/configs/emacs/">0001-01-01 | Emacs config</a></li>
<li><a href="https://sqrtminusone.xyz/configs/guix/">0001-01-01 | Guix</a></li>
<li><a href="https://sqrtminusone.xyz/configs/mail/">0001-01-01 | Mail</a></li>
<li><a href="https://sqrtminusone.xyz/configs/readme/">0001-01-01 | My dotfiles</a></li>
</ul>
</div>
</div><div id="footer" class="mb-5">
<hr>
<div class="container text-center">
<a href="https://sqrtminusone.xyz/"><small>Pavel Korytov, 2021</small></a>
</div>
</div>
</body>
</html>

78
public/configs/index.xml Normal file
View file

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Configs on SqrtMinusOne</title>
<link>https://sqrtminusone.xyz/configs/</link>
<description>Recent content in Configs on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language><atom:link href="https://sqrtminusone.xyz/configs/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Console</title>
<link>https://sqrtminusone.xyz/configs/console/</link>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/configs/console/</guid>
<description>#+TOC headlines 6
.profile Environment # export EDITOR=/usr/bin/vim # export BROWSER=/usr/bin/firefox export QT_QPA_PLATFORMTHEME=&amp;#34;qt5ct&amp;#34; export QT_AUTO_SCREEN_SCALE_FACTOR=0 # export GTK2_RC_FILES=&amp;#34;$HOME/.gtkrc-2.0&amp;#34; My paths My script folders
if [ -d &amp;#34;$HOME/bin&amp;#34; ] ; then export PATH=&amp;#34;$HOME/bin:$PATH&amp;#34; export PATH=&amp;#34;$HOME/bin/scripts:$PATH&amp;#34; fi Guix settings Enable extra profiles
if [ -z &amp;#34;$IS_ANDROID&amp;#34; ]; then GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles for i in $GUIX_EXTRA_PROFILES/*; do profile=$i/$(basename &amp;#34;$i&amp;#34;) if [ -f &amp;#34;$profile&amp;#34;/etc/profile ]; then GUIX_PROFILE=&amp;#34;$profile&amp;#34; . &amp;#34;$GUIX_PROFILE&amp;#34;/etc/profile fi export XDG_DATA_DIRS=&amp;#34;$XDG_DATA_DIRS:$profile/share&amp;#34; unset profile done fi Set Jupyter config PATH.</description>
</item>
<item>
<title>Desktop</title>
<link>https://sqrtminusone.xyz/configs/desktop/</link>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/configs/desktop/</guid>
<description>My general desktop environment configuration.
Parts prefixed with (OFF) are not used, but kept for historic purposes. For some reason GitHub&amp;rsquo;s org renderer ignores TODO status, hence such a prefix. Round brackets instead of square ones to prevent GitHub&amp;rsquo;s org renderer from screwing up.
Table of Contents Global customization Colors Xresources Colors in Xresources Fonts Themes Device-specific settings i3wm General settings Managing windows Workspaces Rules Scratchpad Launch script i3 config Gaps &amp;amp; borders Keybindings Move &amp;amp; resize windows OFF (OFF) Intergration with dmenu Integration with rofi Launching apps &amp;amp; misc keybindings Apps Media controls &amp;amp; brightness Screenshots Colors OFF (OFF) i3blocks Keyboard Layout Autostart Polybar Launching General settings Colors Bar config Modules ipstack-vpn weather aw-afk sun SEP TSEP i3 xkeyboard mpd pulseaudio cpu ram-memory swap-memory network date battery Rofi Theme Scripts Buku bookmarks Man pages Flameshot dunst keynav Config Using with picom Picom Shadows Fading Opacity General settings Zathura Various software Browsers Office LaTeX Dev Manifests Flatpak Nix Services Music GNU Mcron ActivityWatch PulseEffects xsettingsd Discord rich presence Polkit Authentication agent Xmodmap VPN Davmail Shepherd config Sync Guix settings Global customization Colors Most of the colors are from the Palenight theme.</description>
</item>
<item>
<title>Emacs config</title>
<link>https://sqrtminusone.xyz/configs/emacs/</link>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/configs/emacs/</guid>
<description>One day we won&amp;rsquo;t hate one another, no young boy will march to war and I will clean up my Emacs config. But that day isn&amp;rsquo;t today.
My Emacs configuration.
As with other files in the repo, parts prefixed with (OFF) are not used but kept for historic purposes.
Table of Contents Primary setup Measure startup speed straight.el use-package Performance Garbage collection Run garbage collection when Emacs is unfocused Misc Native compilation Anaconda &amp;amp; environment Custom file location Private config No littering Global editing configuration General keybindings stuff general.</description>
</item>
<item>
<title>Guix</title>
<link>https://sqrtminusone.xyz/configs/guix/</link>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/configs/guix/</guid>
<description>GNU Guix is (1) a transactional package manager and (2) a GNU/Linux distribution.
My personal selling points are declarative package configuration and transactional upgrades.
References:
Official help System Crafters wiki Pjotr Prins&#39; Guix notes Davil Wilson&amp;rsquo;s YouTube series Table of Contents Contents Profiles Activate profiles Update profiles Channels Systems Base configuration indigo eminence azure System installation Preparation Installation After installation Misc software &amp;amp; notes VPN vpn-start vpn-stop flatpak conda Slack virt-manager wakatime-cli Manifest Contents Contents Profiles Activate profiles Update profiles Channels Systems Base configuration indigo eminence azure System installation Preparation Installation After installation Misc software &amp;amp; notes VPN vpn-start vpn-stop flatpak conda Slack virt-manager wakatime-cli Manifest Profiles A profile is a way to group Guix packages.</description>
</item>
<item>
<title>Mail</title>
<link>https://sqrtminusone.xyz/configs/mail/</link>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/configs/mail/</guid>
<description>My email configration. Currently uses lieer to fetch emails from Gmail, davmail &amp;amp; offlineimap to fetch emails from MS Exchange, notmuch to index, msmtp to send emails. Also using notmuch frontend from Emacs.
My problem with any particular mail setup was that I use Gmail labels quite extensively, and handling these over IMAP is rather awkward. Notmuch seems to be the only software that provides the same first-class support for labels.</description>
</item>
<item>
<title>My dotfiles</title>
<link>https://sqrtminusone.xyz/configs/readme/</link>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/configs/readme/</guid>
<description>A set of my GNU/Linux configuration files.
The majority of the software is configured with literate configuration strategy via Emacs&#39; Org Mode. This way has its advantages and disadvantages, but overall it&amp;rsquo;s pretty nice to keep the configs interweaved with comments in a handful of files.
The files themselves are managed and deployed via yadm, but I mostly use Org Mode rich noweb whenever I can instead of what yadm offers.</description>
</item>
</channel>
</rss>

View file

@ -0,0 +1,604 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Mail</title>
<meta name="description" content="Freedom is a state of mind">
<meta name="author" content='SqrtMinusOne'>
<link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
</head>
<body><div class="container mt-5">
<nav class="navbar navbar-expand-sm flex-column flex-sm-row text-nowrap p-0">
<a class="navbar-brand mx-0 mr-sm-auto" href="https://sqrtminusone.xyz/">
SqrtMinusOne
</a>
<div class="navbar-nav flex-row flex-wrap justify-content-center">
<a class="nav-item nav-link" href="/">
Index
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/posts/">
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>
</nav>
</div>
<hr>
<div id="content">
<div class="container">
<p>My email configration. Currently uses <a href="https://github.com/gauteh/lieer">lieer</a> to fetch emails from Gmail, <a href="http://davmail.sourceforge.net/">davmail</a> &amp; <a href="http://www.offlineimap.org/">offlineimap</a> to fetch emails from MS Exchange, <a href="https://notmuchmail.org/">notmuch</a> to index, <a href="https://marlam.de/msmtp/">msmtp</a> to send emails. Also using notmuch frontend from Emacs.</p>
<p>My problem with any particular mail setup was that I use Gmail labels quite extensively, and handling these over IMAP is rather awkward. Notmuch seems to be the only software that provides the same first-class support for labels.</p>
<p>But I also have an Exchange account, with which I communicate via IMAP/SMTP adapter, and in this case, I synchronize notmuch tags and IMAP folders.</p>
<p>References:</p>
<ul>
<li><a href="https://sqrtminusone.xyz/posts/2021-02-27-gmail/">My post</a> about email configuration. I wrote it some time ago, but the general idea remains.</li>
</ul>
<div class="ox-hugo-toc toc">
<div></div>
<div class="heading">Table of Contents</div>
<ul>
<li><a href="#lieer">Lieer</a></li>
<li><a href="#davmail">DavMail</a></li>
<li><a href="#offlineimap">OfflineIMAP</a></li>
<li><a href="#notmuch">Notmuch</a>
<ul>
<li><a href="#config">Config</a></li>
<li><a href="#hooks">Hooks</a>
<ul>
<li><a href="#pre-new"><code>pre_new</code></a></li>
<li><a href="#post-new"><code>post_new</code></a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#sync-script">Sync script</a></li>
<li><a href="#msmtp">MSMTP</a></li>
<li><a href="#emacs">Emacs</a>
<ul>
<li><a href="#saved-filters-and-keybindings">Saved filters and keybindings</a></li>
<li><a href="#signing-messages">Signing messages</a></li>
</ul>
</li>
<li><a href="#mailcap">mailcap</a></li>
<li><a href="#guix-settings">Guix settings</a></li>
</ul>
</div>
<!--endtoc-->
<h2 id="lieer">Lieer</h2>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>python-lieer</td>
</tr>
</tbody>
</table>
<p>Lieer is a program to link up Gmail and notmuch. Basically, it downloads mail from Gmail via API, stores them in Maildir, and synchronizes labels with notmuch.</p>
<p>I have a separate directory in my <code>~/Mail</code> for each address. To init lieer, run the following command in the directory:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">gmi init &lt;address&gt;
</code></pre></div><p>After which the settings will be stored in <code>gmailieer.json</code> and the credentials in <code>.credentials.gmailieer.json</code>. The latter file is stored encrypted.</p>
<p>My preferred settings:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">gmi set --replace-slash-with-dot
gmi set --ignore-tags-local new
</code></pre></div><p>Running <code>gmi sync</code> in the required directory performs the synchronization. The first sync takes a while, the subsequent syncs are pretty fast.</p>
<h2 id="davmail">DavMail</h2>
<p>is a gateway between MS Exchange and the rest of the world, which uses IMAP/SMTP/LDAP/etc. As I have one corporate MS Exchange address, this is just the program I need. As of yet, it isn&rsquo;t packaged for Guix, but it&rsquo;s easy enough to download.</p>
<p>It has a GUI mode, but I prefer headless config.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ini" data-lang="ini"><span style="color:#a6e22e">davmail.server</span><span style="color:#f92672">=</span><span style="color:#e6db74">true</span>
<span style="color:#a6e22e">davmail.mode</span><span style="color:#f92672">=</span><span style="color:#e6db74">Auto</span>
<span style="color:#a6e22e">davmail.url</span><span style="color:#f92672">=</span><span style="color:#e6db74">https://mail.etu.ru/owa/</span>
<span style="color:#a6e22e">davmail.caldavPort</span><span style="color:#f92672">=</span><span style="color:#e6db74">1080</span>
<span style="color:#a6e22e">davmail.imapPort</span><span style="color:#f92672">=</span><span style="color:#e6db74">1143</span>
<span style="color:#a6e22e">davmail.ldapPort</span><span style="color:#f92672">=</span><span style="color:#e6db74">1389</span>
<span style="color:#a6e22e">davmail.popPort</span><span style="color:#f92672">=</span><span style="color:#e6db74">1110</span>
<span style="color:#a6e22e">davmail.smtpPort</span><span style="color:#f92672">=</span><span style="color:#e6db74">1025</span>
<span style="color:#a6e22e">davmail.imapAutoExpunge</span><span style="color:#f92672">=</span><span style="color:#e6db74">false</span>
<span style="color:#a6e22e">davmail.enableKeepalive</span><span style="color:#f92672">=</span><span style="color:#e6db74">false</span>
</code></pre></div><p>Also it&rsquo;s a bit of problem to get it launched as it looks for some jars in pwd, so here is a script.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">cd $HOME/bin/davmail-6.0.0-3375
./davmail davmail.properties
</code></pre></div><p>Shepherd service is defined in <a href="/configs/desktop/">Desktop.org</a>.</p>
<h2 id="offlineimap">OfflineIMAP</h2>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>offlineimap</td>
</tr>
</tbody>
</table>
<p><a href="https://github.com/OfflineIMAP/offlineimap">OfflineIMAP</a> is a program that can synchronize IMAP mailbox and Maildir. Lieer does everything by itself, but my pirate Exchange IMAP needs this program. There is also <a href="https://isync.sourceforge.io/">isync</a>, but I had some weird issues with duplicate UIDs, which don&rsquo;t occur for OfflineIMAP.</p>
<p>I have a few options for setting a username and password. First, I can run <code>pass</code> in <code>remotepasswordeval</code>, and this is fine, but it will keep by keyring unlocked because I want to run <code>offlineimap</code> every couple of minutes.</p>
<p>Another option is to use noweb and not push the file below to the version control. Then I have a plaintext password of email on my computer, but I think it&rsquo;s a lesser evil than the entire keyring.</p>
<p>I would use <code>password-store-get</code> from password-store.el, but I want this to be able to run without any 3rd party packages, so it&rsquo;s just bash.</p>
<p><a id="code-snippet--mail-username"></a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">pass show Job/Infrastructure/pvkorytov@etu.ru | sed -n <span style="color:#e6db74">&#39;s/username: //;2p&#39;</span>
</code></pre></div><p><a id="code-snippet--mail-password"></a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">pass show Job/Infrastructure/pvkorytov@etu.ru | head -n <span style="color:#ae81ff">1</span>
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ini" data-lang="ini"><span style="color:#66d9ef">[general]</span>
<span style="color:#a6e22e">accounts</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">pvkorytov</span>
<span style="color:#66d9ef">[Account pvkorytov]</span>
<span style="color:#a6e22e">localrepository</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">pvkorytov-local</span>
<span style="color:#a6e22e">remoterepository</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">pvkorytov-remote</span>
<span style="color:#66d9ef">[Repository pvkorytov-local]</span>
<span style="color:#a6e22e">type</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">Maildir</span>
<span style="color:#a6e22e">localfolders</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">~/Mail/pvkorytov_etu/</span>
<span style="color:#66d9ef">[Repository pvkorytov-remote]</span>
<span style="color:#a6e22e">type</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">IMAP</span>
<span style="color:#a6e22e">remotehost</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">localhost</span>
<span style="color:#a6e22e">remoteuser</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&lt;&lt;mail-username()&gt;&gt;</span>
<span style="color:#a6e22e">remotepass</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&lt;&lt;mail-password()&gt;&gt;</span>
<span style="color:#a6e22e">remoteport</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">1143</span>
<span style="color:#a6e22e">starttls</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">no</span>
<span style="color:#a6e22e">ssl</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">no</span>
</code></pre></div><h2 id="notmuch">Notmuch</h2>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>notmuch</td>
</tr>
<tr>
<td>parallel</td>
</tr>
</tbody>
</table>
<p>Notmuch is an email indexer program, which handles labels in a way somewhat like Gmail. It also provides a frontend for Emacs, but it&rsquo;s not the only one available.</p>
<h3 id="config">Config</h3>
<p>Not much is going on here.</p>
<p>First, the database path.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ini" data-lang="ini"><span style="color:#66d9ef">[database]</span>
<span style="color:#a6e22e">path</span><span style="color:#f92672">=</span><span style="color:#e6db74">/home/pavel/Mail</span>
</code></pre></div><p>My name and list of emails. It&rsquo;s not like it&rsquo;s a secret anyhow.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ini" data-lang="ini"><span style="color:#66d9ef">[user]</span>
<span style="color:#a6e22e">name</span><span style="color:#f92672">=</span><span style="color:#e6db74">Pavel Korytov</span>
<span style="color:#a6e22e">primary_email</span><span style="color:#f92672">=</span><span style="color:#e6db74">thexcloud@gmail.com</span>
<span style="color:#a6e22e">other_email</span><span style="color:#f92672">=</span><span style="color:#e6db74">progin6304@gmail.com;pvkorytov@etu.ru</span>
</code></pre></div><p>A list of tags which will be added by <code>notmuch new</code> and directory names which will be ignored by <code>notmuch new</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ini" data-lang="ini"><span style="color:#66d9ef">[new]</span>
<span style="color:#a6e22e">tags</span><span style="color:#f92672">=</span><span style="color:#e6db74">new;</span>
<span style="color:#a6e22e">ignore</span><span style="color:#f92672">=</span><span style="color:#e6db74">.osync_workdir;.mbsyncstate;.uidvalidity;.lock;/.*gmailieer\.json.*/</span>
</code></pre></div><p>Exclude these tags from search by default.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ini" data-lang="ini"><span style="color:#66d9ef">[search]</span>
<span style="color:#a6e22e">exclude_tags</span><span style="color:#f92672">=</span><span style="color:#e6db74">trash;spam;</span>
</code></pre></div><p>Maildir compatibility.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ini" data-lang="ini"><span style="color:#66d9ef">[maildir]</span>
<span style="color:#a6e22e">synchronize_flags</span><span style="color:#f92672">=</span><span style="color:#e6db74">true</span>
</code></pre></div><h3 id="hooks">Hooks</h3>
<p>Now we have to link up lieer &amp; Maildir and with notmuch. This is done via the notmuch hook system, which allows running custom scripts before and after any command.</p>
<p>With lieer and Gmail, it is enough to simply run the program, because Gmail has first-class support for tags. Maildir does not, so I decide to synchronize notmuch tags and IMAP folders. In essence, the idea is to:</p>
<ul>
<li>move emails to their folders by tags <em>before</em> the synchronization</li>
<li>tag mails by their folders <em>after</em> the synchronization</li>
</ul>
<p>The problem is that with that approach one email can have only one tag, but it&rsquo;s better than nothing.</p>
<p>So, here are the rules which match tags &amp; folders:</p>
<p><a id="table--pvkorytov-tags"></a></p>
<table>
<thead>
<tr>
<th>tag</th>
<th>folder</th>
</tr>
</thead>
<tbody>
<tr>
<td>inbox</td>
<td>INBOX</td>
</tr>
<tr>
<td>sent</td>
<td>Sent</td>
</tr>
<tr>
<td>spam</td>
<td>Junk</td>
</tr>
<tr>
<td>trash</td>
<td>Trash</td>
</tr>
<tr>
<td>job.digital</td>
<td>Job_Digital</td>
</tr>
<tr>
<td>job.digital.docs</td>
<td>Job_Digital.Docs</td>
</tr>
<tr>
<td>job.digital.support</td>
<td>Job_Digital.Support</td>
</tr>
<tr>
<td>job.digital.superservice</td>
<td>Job_Digital.Superservice</td>
</tr>
</tbody>
</table>
<p>And below is a noweb function, which generates the following commands for notmuch to execute:</p>
<ul>
<li><em>before</em> sync:
<ul>
<li><code>notmuch search --output files &quot;NOT path:[PATH] AND tag:[TAG] AND tag:[ROOT_TAG]&quot; | xargs -I ! mv ! [PATH]</code>
Move emails with <code>TAG</code> but outside the matching <code>PATH</code> to the latter</li>
<li><code>notmuch search --output=files &quot;NOT path:[ARCHIVE_PATH] AND tag:[ROOT_TAG] AND NOT tag:[TAG1] ... AND NOT tag:[TAGN]&quot; | xargs -I ! mv ! [ARCHIVE_PATH]</code>
Move untagged emails to the <code>ARCHIVE_PATH</code></li>
</ul>
</li>
<li><em>after</em> sync:
<ul>
<li><code>notmuch tag +[TAG] &quot;path:[PATH] AND NOT tag:[TAG]&quot;</code>
Tag emails in <code>PATH</code> which do not yet have the matching <code>TAG</code></li>
<li><code>notmuch tag -[TAG] &quot;NOT path:[PATH] AND tag:[TAG] AND tag:[ROOT_TAG]&quot;</code>
Remove <code>TAG</code> from emails which are outside the matching <code>PATH</code></li>
</ul>
</li>
</ul>
<p>These rules are getting included in the respective hooks.</p>
<p><a id="code-snippet--mail-tags"></a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq my/maildir-root <span style="color:#e6db74">&#34;~/Mail&#34;</span>)
(let ((rules <span style="color:#f92672">&#39;</span>()))
(dolist (row tags)
(let ((tag (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> row))
(folder (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> row)))
(unless (string-empty-p make_tag)
(add-to-list
<span style="color:#e6db74">&#39;rules</span>
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;notmuch tag +%s \&#34;path:%s/%s/cur/** AND NOT tag:%s\&#34;&#34;</span>
tag root folder tag)
<span style="color:#66d9ef">t</span>))
(unless (string-empty-p remove)
(add-to-list
<span style="color:#e6db74">&#39;rules</span>
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;notmuch tag -%s \&#34;NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\&#34;&#34;</span>
tag root folder tag root_tag)
<span style="color:#66d9ef">t</span>))
(unless (string-empty-p move)
(add-to-list
<span style="color:#e6db74">&#39;rules</span>
(<span style="color:#a6e22e">concat</span>
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;notmuch search --output=files \&#34;NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\&#34;&#34;</span>
root folder tag root_tag)
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34; | xargs -I ! mv ! %s/%s/%s/cur/&#34;</span> my/maildir-root root folder))
<span style="color:#66d9ef">t</span>))))
(unless (string-empty-p archive_root)
(add-to-list
<span style="color:#e6db74">&#39;rules</span>
(<span style="color:#a6e22e">concat</span>
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;notmuch search --output=files \&#34;NOT path:%s/%s/cur/** AND %s AND tag:%s\&#34;&#34;</span>
root archive_root
(<span style="color:#a6e22e">mapconcat</span>
(lambda (row)
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;NOT tag:%s&#34;</span> (<span style="color:#a6e22e">car</span> row)))
tags
<span style="color:#e6db74">&#34; AND &#34;</span>)
root_tag)
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34; | xargs -I ! mv ! %s/%s/%s/cur/&#34;</span> my/maildir-root root archive_root))
<span style="color:#66d9ef">t</span>))
(string-join rules <span style="color:#e6db74">&#34;\n&#34;</span>))
</code></pre></div><h4 id="pre-new"><code>pre_new</code></h4>
<p>This hook runs fetch from Gmail &amp; offlineimap in parallel before the <code>notmuch new</code> command. The <code>parallel</code> command is provided by <a href="https://www.gnu.org/software/parallel/">GNU Parallel</a>.</p>
<p>It isn&rsquo;t necessary to run <code>cd</code> for offlineimap, but it&rsquo;s easier to write that way.</p>
<p><a id="code-snippet--pre-new-pvkorytov-tags"></a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(my/mail-format-tags-rules tags <span style="color:#e6db74">&#34;pvkorytov_etu&#34;</span> <span style="color:#e6db74">&#34;pvkorytov&#34;</span> <span style="color:#66d9ef">nil</span> <span style="color:#66d9ef">nil</span> <span style="color:#66d9ef">t</span> <span style="color:#e6db74">&#34;Archive&#34;</span>)
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e"># GMI=&#34;/home/pavel/Programs/miniconda3/envs/mail/bin/gmi&#34;</span>
GMI<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;gmi&#34;</span>
echo <span style="color:#e6db74">&#34;Running pre-new filters&#34;</span>
<span style="color:#e6db74">&lt;&lt;mail-tags(move=&#34;t&#34;,archive_root=&#34;Archive&#34;)&gt;&gt;
</span><span style="color:#e6db74">echo &#34;Pre-new filters done&#34;
</span><span style="color:#e6db74">
</span><span style="color:#e6db74">parallel --link -j0 &#34;(cd /home/pavel/Mail/{1}/ &amp;&amp; {2} {3})&#34; ::: thexcloud progin6304 pvkorytov_etu ::: &#34;$GMI&#34; &#34;$GMI&#34; &#34;offlineima</span>p<span style="color:#e6db74">&#34; ::: sync sync &#34;&#34;
</span></code></pre></div><h4 id="post-new"><code>post_new</code></h4>
<p>And this hook tags different mailboxes with different tags.</p>
<p><a id="code-snippet--post-new-pvkorytov-tags"></a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(my/mail-format-tags-rules tags <span style="color:#e6db74">&#34;pvkorytov_etu&#34;</span> <span style="color:#e6db74">&#34;pvkorytov&#34;</span> <span style="color:#66d9ef">t</span> <span style="color:#66d9ef">t</span>)
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">notmuch tag +main <span style="color:#e6db74">&#34;path:thexcloud/** AND tag:new&#34;</span>
notmuch tag +progin <span style="color:#e6db74">&#34;path:progin6304/** AND tag:new&#34;</span>
notmuch tag +pvkorytov <span style="color:#e6db74">&#34;path:pvkorytov_etu/** AND tag:new&#34;</span>
echo <span style="color:#e6db74">&#34;Running post-new filters&#34;</span>
<span style="color:#e6db74">&lt;&lt;mail-tags(ma</span>ke_tag<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;t&#34;</span>,remove<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;t&#34;</span><span style="color:#f92672">)</span>&gt;&gt;
echo <span style="color:#e6db74">&#34;Post-new filters done&#34;</span>
notmuch tag -new <span style="color:#e6db74">&#34;tag:new&#34;</span>
</code></pre></div><h2 id="sync-script">Sync script</h2>
<p>A script to run <code>notmuch new</code> and push a notification if there is new mail.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">export DISPLAY<span style="color:#f92672">=</span>:0
CHECK_FILE<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/home/pavel/Mail/.last_check&#34;</span>
QUERY<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;tag:unread&#34;</span>
ALL_QUERY<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;tag:unread&#34;</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -f <span style="color:#e6db74">&#34;</span>$CHECK_FILE<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
DATE<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>cat <span style="color:#e6db74">&#34;</span>$CHECK_FILE<span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">)</span>
QUERY<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$QUERY<span style="color:#e6db74"> and date:@</span>$DATE<span style="color:#e6db74">..&#34;</span>
<span style="color:#66d9ef">fi</span>
notmuch new
NEW_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">&#34;</span>$QUERY<span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">)</span>
ALL_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">&#34;</span>$ALL_QUERY<span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">)</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> $NEW_UNREAD -gt <span style="color:#ae81ff">0</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
MAIN_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">&#34;tag:unread AND tag:main&#34;</span><span style="color:#66d9ef">)</span>
PROGIN_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">&#34;tag:unread AND tag:progin&#34;</span><span style="color:#66d9ef">)</span>
ETU_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">&#34;tag:unread AND tag:pvkorytov&#34;</span><span style="color:#66d9ef">)</span>
read -r -d <span style="color:#e6db74">&#39;&#39;</span> NOTIFICATION <span style="color:#e6db74">&lt;&lt;EOM
</span><span style="color:#e6db74">$NEW_UNREAD new messages
</span><span style="color:#e6db74">$MAIN_UNREAD thexcloud@gmail.com
</span><span style="color:#e6db74">$PROGIN_UNREAD progin6304@gmail.com
</span><span style="color:#e6db74">$ETU_UNREAD pvkorytov@etu.ru
</span><span style="color:#e6db74">$ALL_UNREAD total
</span><span style="color:#e6db74">EOM</span>
notify-send <span style="color:#e6db74">&#34;New Mail&#34;</span> <span style="color:#e6db74">&#34;</span>$NOTIFICATION<span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">fi</span>
echo <span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>date +%s<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span> &gt; $CHECK_FILE
</code></pre></div><p>The script is ran via GNU Mcron every 5 minutes.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#a6e22e">job</span> <span style="color:#e6db74">&#34;*/5 * * * * &#34;</span> <span style="color:#e6db74">&#34;~/bin/scripts/check-email&#34;</span>)
</code></pre></div><h2 id="msmtp">MSMTP</h2>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>msmtp</td>
</tr>
</tbody>
</table>
<p>Sending emails can be done with MSMTP. It automatially chooses the email address and server based on the contents of the message, which is handy if there are multiple mailboxes to be managed.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vim" data-lang="vim"><span style="color:#a6e22e">defaults</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">auth</span> <span style="color:#a6e22e">on</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">tls</span> <span style="color:#a6e22e">on</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">tls_trust_file</span> <span style="color:#e6db74">/etc/</span><span style="color:#a6e22e">ssl</span><span style="color:#e6db74">/certs/</span><span style="color:#a6e22e">ca</span>-<span style="color:#a6e22e">certificates</span>.<span style="color:#a6e22e">crt</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">logfile</span> ~/.<span style="color:#a6e22e">msmtp</span>.<span style="color:#a6e22e">log</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">account</span> <span style="color:#a6e22e">main</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">host</span> <span style="color:#a6e22e">smtp</span>.<span style="color:#a6e22e">gmail</span>.<span style="color:#a6e22e">com</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">port</span> <span style="color:#ae81ff">587</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">from</span> <span style="color:#a6e22e">thexcloud</span>@<span style="color:#a6e22e">gmail</span>.<span style="color:#a6e22e">com</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">user</span> <span style="color:#a6e22e">thexcloud</span>@<span style="color:#a6e22e">gmail</span>.<span style="color:#a6e22e">com</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">passwordeval</span> <span style="color:#e6db74">&#34;pass show My_Online/APIs/google-main-app-password | head -n 1&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">account</span> <span style="color:#a6e22e">progin</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">host</span> <span style="color:#a6e22e">smtp</span>.<span style="color:#a6e22e">gmail</span>.<span style="color:#a6e22e">com</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">port</span> <span style="color:#ae81ff">587</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">from</span> <span style="color:#a6e22e">progin6304</span>@<span style="color:#a6e22e">gmail</span>.<span style="color:#a6e22e">com</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">user</span> <span style="color:#a6e22e">progin6304</span>@<span style="color:#a6e22e">gmail</span>.<span style="color:#a6e22e">com</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">passwordeval</span> <span style="color:#e6db74">&#34;pass show My_Online/ETU/progin6304@gmail.com | head -n 1&#34;</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">account</span> <span style="color:#a6e22e">pvkorytov</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">tls</span> <span style="color:#a6e22e">off</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">auth</span> <span style="color:#a6e22e">plain</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">host</span> <span style="color:#a6e22e">localhost</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">port</span> <span style="color:#ae81ff">1025</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">from</span> <span style="color:#a6e22e">pvkorytov</span>@<span style="color:#a6e22e">etu</span>.<span style="color:#a6e22e">ru</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">user</span> <span style="color:#a6e22e">pvkorytov</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">passwordeval</span> <span style="color:#e6db74">&#34;pass show Job/Infrastructure/pvkorytov@etu.ru | head -n 1&#34;</span><span style="color:#960050;background-color:#1e0010">
</span></code></pre></div><h2 id="emacs">Emacs</h2>
<p>Finally, Emacs configuration. Let&rsquo;s start with some variables:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq user-mail-address <span style="color:#e6db74">&#34;thexcloud@gmail.com&#34;</span>)
(setq <span style="color:#a6e22e">user-full-name</span> <span style="color:#e6db74">&#34;Pavel Korytov&#34;</span>)
</code></pre></div><p>Then, the problem with my Guix setup is that Emacs by default doesn&rsquo;t see the elisp files of notmuch, so here is a small workaround:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(let ((default-directory <span style="color:#e6db74">&#34;/home/pavel/.guix-extra-profiles/mail/mail/share/emacs/site-lisp&#34;</span>))
(normal-top-level-add-subdirs-to-load-path))
</code></pre></div><p>Finally the proper notmuch settings:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package notmuch
<span style="color:#75715e">;; :ensure nil</span>
:commands (notmuch notmuch-search)
:config
(setq mail-specify-envelope-from <span style="color:#66d9ef">t</span>)
(setq message-sendmail-envelope-from <span style="color:#e6db74">&#39;header</span>)
(setq mail-envelope-from <span style="color:#e6db74">&#39;header</span>)
(setq notmuch-always-prompt-for-sender <span style="color:#66d9ef">t</span>)
(setq sendmail-program (executable-find <span style="color:#e6db74">&#34;msmtp&#34;</span>))
(setq send-mail-function <span style="color:#a6e22e">#&#39;</span>sendmail-send-it)
(setq mml-secure-openpgp-sign-with-sender <span style="color:#66d9ef">t</span>)
(setq notmuch-mua-user-agent-function <span style="color:#e6db74">&#39;notmuch-mua-user-agent-full</span>)
(add-hook <span style="color:#e6db74">&#39;notmuch-hello-mode-hook</span>
(lambda () (display-line-numbers-mode <span style="color:#ae81ff">0</span>))))
</code></pre></div><p>The file to which this is tangled is read in the init.el.</p>
<h3 id="saved-filters-and-keybindings">Saved filters and keybindings</h3>
<p>I want to have the saved filters available in both notmuch interface as as keybindings. So a bit more of abusing org tables.</p>
<p>Root keybindings:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(my-leader-def
:infix <span style="color:#e6db74">&#34;am&#34;</span>
<span style="color:#e6db74">&#34;&#34;</span> <span style="color:#f92672">&#39;</span>(:which-key <span style="color:#e6db74">&#34;notmuch&#34;</span>)
<span style="color:#e6db74">&#34;m&#34;</span> <span style="color:#e6db74">&#39;notmuch</span>)
</code></pre></div><p><a id="table--root-tags"></a></p>
<table>
<thead>
<tr>
<th>Root tag</th>
<th>Prefix</th>
<th>Keybinding description</th>
</tr>
</thead>
<tbody>
<tr>
<td>main</td>
<td>t</td>
<td><a href="mailto:thexcloud@gmail.com">thexcloud@gmail.com</a></td>
</tr>
<tr>
<td>progin</td>
<td>p</td>
<td><a href="mailto:progin6304@gmail.com">progin6304@gmail.com</a></td>
</tr>
<tr>
<td>pvkorytov</td>
<td>e</td>
<td><a href="mailto:pvkorytov@etu.ru">pvkorytov@etu.ru</a></td>
</tr>
</tbody>
</table>
<p><a id="table--filter-tags"></a></p>
<table>
<thead>
<tr>
<th>Tag</th>
<th>Prefix</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>inbox</td>
<td>i</td>
<td>inbox</td>
</tr>
<tr>
<td>unread</td>
<td>u</td>
<td>unread</td>
</tr>
<tr>
<td>sent</td>
<td>s</td>
<td>sent</td>
</tr>
<tr>
<td></td>
<td>a</td>
<td>all mail</td>
</tr>
</tbody>
</table>
<p>The following formats the tables above to a proper syntax for <code>setq notmuch-saved-searches</code>:</p>
<p><a id="code-snippet--format-notmuch-saved-searches"></a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(let ((searches <span style="color:#f92672">&#39;</span>()))
(dolist (root_tag root_tags)
(dolist (tag filter_tags)
(add-to-list
<span style="color:#e6db74">&#39;searches</span>
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;(:name \&#34;%s\&#34; :query \&#34;%s\&#34;)&#34;</span>
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;%s (%s)&#34;</span>
(<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> root_tag)
(<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">2</span> tag))
(<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;tag:&#34;</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> root_tag)
(unless (string-empty-p (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> tag))
(<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34; AND tag:&#34;</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> tag)))))
<span style="color:#66d9ef">t</span>)))
(string-join searches <span style="color:#e6db74">&#34;\n&#34;</span>))
</code></pre></div><p>And the following does the same for my general.el definer:</p>
<p><a id="code-snippet--format-notmuch-keybindings"></a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(let ((bindings <span style="color:#f92672">&#39;</span>()))
(dolist (root_tag root_tags)
(add-to-list
<span style="color:#e6db74">&#39;bindings</span>
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;\&#34;%s\&#34; &#39;(:which-key \&#34;%s\&#34;)&#34;</span>
(<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> root_tag)
(<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">2</span> root_tag))
<span style="color:#66d9ef">t</span>)
(dolist (tag filter_tags)
(add-to-list
<span style="color:#e6db74">&#39;bindings</span>
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;\&#34;%s\&#34; &#39;((lambda () (interactive) (notmuch-search \&#34;%s\&#34;)) :which-key \&#34;%s\&#34;)&#34;</span>
(<span style="color:#a6e22e">concat</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> root_tag) (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> tag))
(<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;tag:&#34;</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> root_tag)
(unless (string-empty-p (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> tag))
(<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34; AND tag:&#34;</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> tag))))
(<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">2</span> tag))
<span style="color:#66d9ef">t</span>)))
(string-join bindings <span style="color:#e6db74">&#34;\n&#34;</span>))
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq notmuch-saved-searches
<span style="color:#f92672">&#39;</span>((:name <span style="color:#e6db74">&#34;drafts&#34;</span> :query <span style="color:#e6db74">&#34;tag:draft&#34;</span>)
&lt;&lt;format-notmuch-saved-searches()&gt;&gt;))
(my-leader-def
:infix <span style="color:#e6db74">&#34;am&#34;</span>
&lt;&lt;format-notmuch-keybindings()&gt;&gt;)
</code></pre></div><h3 id="signing-messages">Signing messages</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(with-eval-after-load <span style="color:#e6db74">&#39;notmuch</span>
(add-hook <span style="color:#e6db74">&#39;message-setup-hook</span> <span style="color:#e6db74">&#39;mml-secure-sign-pgpmime</span>))
(setq mml-secure-key-preferences
<span style="color:#f92672">&#39;</span>((OpenPGP
(sign
(<span style="color:#e6db74">&#34;thexcloud@gmail.com&#34;</span> <span style="color:#e6db74">&#34;914472A1FD6775C166F96EBEED739ADF81C78160&#34;</span>))
(encrypt))
(CMS
(sign)
(encrypt))))
</code></pre></div><h2 id="mailcap">mailcap</h2>
<p>mailcap file is a file which defines how to read to different MIME types. Notmuch also uses it, so why not keep it here.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">audio/*; mpc add %s
image/*; feh %s
application/msword; /usr/bin/xdg-open %s
application/pdf; zathura %s
application/postscript ; zathura %s
text/html; firefox %s
</code></pre></div><h2 id="guix-settings">Guix settings</h2>
<p><a id="code-snippet--packages"></a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(my/format-guix-dependencies)
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#a6e22e">specifications-&gt;manifest</span>
<span style="color:#f92672">&#39;</span>(
&lt;&lt;packages()&gt;&gt;))
</code></pre></div>
</div>
</div><div id="footer" class="mb-5">
<hr>
<div class="container text-center">
<a href="https://sqrtminusone.xyz/"><small>Pavel Korytov, 2021</small></a>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,381 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>My dotfiles</title>
<meta name="description" content="Freedom is a state of mind">
<meta name="author" content='SqrtMinusOne'>
<link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
</head>
<body><div class="container mt-5">
<nav class="navbar navbar-expand-sm flex-column flex-sm-row text-nowrap p-0">
<a class="navbar-brand mx-0 mr-sm-auto" href="https://sqrtminusone.xyz/">
SqrtMinusOne
</a>
<div class="navbar-nav flex-row flex-wrap justify-content-center">
<a class="nav-item nav-link" href="/">
Index
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/posts/">
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>
</nav>
</div>
<hr>
<div id="content">
<div class="container">
<figure><img src="https://forthebadge.com/images/badges/works-on-my-machine.svg"/>
</figure>
<p>A set of my GNU/Linux configuration files.</p>
<p>The majority of the software is configured with <a href="https://leanpub.com/lit-config/read">literate configuration</a> strategy via Emacs' Org Mode. This way has its advantages and disadvantages, but overall it&rsquo;s pretty nice to keep the configs interweaved with comments in a handful of files.</p>
<p>The files themselves are managed and deployed via <a href="https://yadm.io/">yadm</a>, but I mostly use Org Mode rich noweb whenever I can instead of what yadm offers.</p>
<p>My current GNU/Linux distribution is <a href="https://guix.gnu.org/">GNU Guix</a>. In the context of this repo, Guix allows me to list all the used programs in manifests, which means I have the same set of programs across multiple machines. Looks for Org tables with &ldquo;Guix dependency&rdquo; in the header.</p>
<p>Literate configuration files:</p>
<ul>
<li><a href="/configs/emacs/">Emacs.org</a></li>
<li><a href="/configs/desktop/">Desktop.org</a></li>
<li><a href="/configs/console/">Console.org</a></li>
<li><a href="/configs/guix/">Guix.org</a></li>
<li><a href="/configs/mail/">Mail.org</a></li>
</ul>
<h2 id="programs-used">Programs used</h2>
<p>Some of the notable programs are listed in the table below.</p>
<table>
<thead>
<tr>
<th>Group</th>
<th>Program</th>
<th>Purpose</th>
<th>Status</th>
<th>Documented?</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>console</td>
<td>bash</td>
<td>shell</td>
<td>launches fish :)</td>
<td><a href="/configs/console/">Console.org</a></td>
<td></td>
</tr>
<tr>
<td>console</td>
<td><a href="https://fishshell.com/">fish</a></td>
<td>shell</td>
<td><strong>active</strong></td>
<td><a href="/configs/console/">Console.org</a></td>
<td></td>
</tr>
<tr>
<td>console</td>
<td><a href="https://github.com/starship/starship">starship</a></td>
<td>prompt</td>
<td><strong>active</strong></td>
<td><a href="/configs/console/">Console.org</a></td>
<td></td>
</tr>
<tr>
<td>console</td>
<td><a href="https://github.com/tmux/tmux">tmux</a></td>
<td>terminal multiplexer</td>
<td><strong>active</strong></td>
<td><a href="/configs/console/">Console.org</a></td>
<td></td>
</tr>
<tr>
<td>console</td>
<td><a href="https://github.com/alacritty/alacritty">alacritty</a></td>
<td>terminal emulator</td>
<td><strong>active</strong></td>
<td><a href="/configs/console/">Console.org</a></td>
<td></td>
</tr>
<tr>
<td>mail</td>
<td><a href="https://notmuchmail.org/">notmuch</a></td>
<td>mail indexer</td>
<td><strong>active</strong></td>
<td><a href="/configs/mail/">Mail.org,</a> <a href="https://sqrtminusone.xyz/posts/2021-02-27-gmail/">post</a></td>
<td></td>
</tr>
<tr>
<td>mail</td>
<td><a href="https://github.com/gauteh/lieer">lieer</a></td>
<td>gmail API client</td>
<td><strong>active</strong></td>
<td><a href="/configs/mail/">Mail.org</a>, <a href="https://sqrtminusone.xyz/posts/2021-02-27-gmail/">post</a></td>
<td>credentials are encrypted</td>
</tr>
<tr>
<td>mail</td>
<td><a href="https://marlam.de/msmtp/">msmtp</a></td>
<td>SMTP client</td>
<td><strong>active</strong></td>
<td><a href="/configs/mail/">Mail.org</a></td>
<td></td>
</tr>
<tr>
<td>editor</td>
<td><a href="https://www.gnu.org/software/emacs/">emacs</a></td>
<td>everything</td>
<td><strong>active</strong></td>
<td><a href="/configs/emacs/">Emacs.org</a></td>
<td>GitHub renders .org files without labels and <code>tangle: no</code></td>
</tr>
<tr>
<td>editor</td>
<td><a href="https://www.vim.org/">vim</a></td>
<td>text edtior</td>
<td><strong>active</strong></td>
<td>-</td>
<td>A minimal config to have a lightweight terminal $EDITOR</td>
</tr>
<tr>
<td>editor</td>
<td><a href="https://neovim.io/">neovim</a></td>
<td>text edtior</td>
<td>archive</td>
<td>-</td>
<td></td>
</tr>
<tr>
<td>documents</td>
<td><a href="https://mg.readthedocs.io/latexmk.html">latexmk</a></td>
<td>LaTeX build tool</td>
<td><strong>active</strong></td>
<td>-</td>
<td></td>
</tr>
<tr>
<td>documents</td>
<td><a href="https://pwmt.org/projects/zathura/">zathura</a></td>
<td>pdf viewer</td>
<td><strong>active</strong></td>
<td><a href="/configs/desktop/">Desktop.org</a></td>
<td></td>
</tr>
<tr>
<td>desktop</td>
<td><a href="https://github.com/dunst-project/dunst">dunst</a></td>
<td>notification manager</td>
<td><strong>active</strong></td>
<td><a href="/configs/desktop/">Desktop.org</a></td>
<td></td>
</tr>
<tr>
<td>desktop</td>
<td><a href="https://i3wm.org/">i3wm</a></td>
<td>tiling WM</td>
<td><strong>active</strong></td>
<td><a href="/configs/desktop/">Desktop.org</a></td>
<td></td>
</tr>
<tr>
<td>desktop</td>
<td><a href="https://github.com/jordansissel/keynav">keynav</a></td>
<td>control mouse with keyboard</td>
<td><strong>active</strong></td>
<td><a href="/configs/desktop/">Desktop.org</a></td>
<td></td>
</tr>
<tr>
<td>desktop</td>
<td><a href="https://github.com/polybar/polybar">polybar</a></td>
<td>status bar</td>
<td><strong>active</strong></td>
<td><a href="/configs/desktop/">Desktop.org</a></td>
<td></td>
</tr>
<tr>
<td>desktop</td>
<td><a href="https://github.com/davatorium/rofi">rofi</a></td>
<td>generic menu</td>
<td><strong>active</strong></td>
<td><a href="/configs/desktop/">Desktop.org</a></td>
<td></td>
</tr>
<tr>
<td>desktop</td>
<td><a href="https://github.com/flameshot-org/flameshot">flameshot</a></td>
<td>screenshot</td>
<td><strong>active</strong></td>
<td><a href="/configs/desktop/">Desktop.org</a></td>
<td></td>
</tr>
<tr>
<td>desktop</td>
<td><a href="https://github.com/yshui/picom">picom</a></td>
<td>X11 compositor</td>
<td><strong>active</strong></td>
<td><a href="/configs/desktop/">Desktop.org</a></td>
<td></td>
</tr>
<tr>
<td>desktop</td>
<td><a href="https://github.com/vivien/i3blocks">i3blocks</a></td>
<td>status bar</td>
<td>archive</td>
<td>-</td>
<td></td>
</tr>
<tr>
<td>internet</td>
<td><a href="https://github.com/tridactyl/tridactyl">tridactyl</a></td>
<td>vim bindings for Firefox</td>
<td><strong>active</strong></td>
<td>-</td>
<td>templated with yadm</td>
</tr>
<tr>
<td>internet</td>
<td><a href="https://newsboat.org/">newsboat</a></td>
<td>terminal RSS reader</td>
<td>archive</td>
<td>-</td>
<td>urls are encrypted</td>
</tr>
<tr>
<td>internet</td>
<td><a href="https://qutebrowser.org/">qutebrowser</a></td>
<td>browser with vim bindings</td>
<td>archive</td>
<td>-</td>
<td></td>
</tr>
<tr>
<td>internet</td>
<td><a href="https://github.com/jarun/buku">buku</a></td>
<td>bookmarks manager</td>
<td>archive</td>
<td>-</td>
<td></td>
</tr>
<tr>
<td>audio</td>
<td><a href="https://www.musicpd.org/">mpd</a></td>
<td>music player daemon</td>
<td><strong>active</strong></td>
<td>-</td>
<td></td>
</tr>
<tr>
<td>audio</td>
<td><a href="https://github.com/ncmpcpp/ncmpcpp">ncmpcpp</a></td>
<td>MPD frontend</td>
<td><strong>active</strong></td>
<td>-</td>
<td></td>
</tr>
<tr>
<td>misc</td>
<td><a href="https://yadm.io">yadm</a></td>
<td>dotfiles manager</td>
<td><strong>active</strong></td>
<td>-</td>
<td></td>
</tr>
<tr>
<td>misc</td>
<td><a href="https://github.com/risacher/sunwait">sunwait</a></td>
<td>sunrise calculator</td>
<td><strong>active</strong></td>
<td>-</td>
<td></td>
</tr>
<tr>
<td>misc</td>
<td><a href="https://github.com/vergoh/vnstat">vnstat</a></td>
<td>traffic stats</td>
<td><strong>active</strong></td>
<td>-</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="posts-about-my-configuration">Posts about my configuration</h2>
<ul>
<li><a href="https://sqrtminusone.xyz/posts/2021-05-01-org-python/">Replacing Jupyter Notebook with Org Mode</a></li>
<li><a href="https://sqrtminusone.xyz/posts/2021-02-27-gmail/">Multiple Gmail accounts &amp; labels with Emacs</a></li>
</ul>
<h2 id="some-statistics">Some statistics</h2>
<p>Run the following to show the pictures with reasonable width:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-elisp" data-lang="elisp">(setq-local org-image-actual-width <span style="color:#f92672">&#39;</span>(<span style="color:#ae81ff">1024</span>))
</code></pre></div><h3 id="history">History</h3>
<figure><img src="/ox-hugo/all.png"/>
</figure>
<figure><img src="/ox-hugo/emacs-vim.png"/>
</figure>
<figure><img src="/ox-hugo/literate-config.png"/>
</figure>
<h2 id="misc">Misc</h2>
<h3 id="notes">Notes</h3>
<ul>
<li><code>M-u C-c C-v t</code> to tangle a particular block</li>
<li><code>M-u M-u C-c C-v t</code> to tangle a particular file</li>
<li><code>C-c C-v d</code> to demarcate a block</li>
</ul>
<p>Uses yadm&rsquo;s <code>post_alt</code> hook to create symlinks</p>
<h3 id="encrypted-files">Encrypted files</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">.config/newsboat/urls
.config/filezilla/sitemanager.xml
.config/filezilla/filezilla.xml
Mail/thexcloud/.credentials.gmailieer.json
Mail/progin6304/.credentials.gmailieer.json
.emacs.d/dired-bookmarks.el
.emacs.d/elfeed.org
.emacs.d/private.org
.emacs.d/prodigy-config.el
.emacs.d/private.el
</code></pre></div>
</div>
</div><div id="footer" class="mb-5">
<hr>
<div class="container text-center">
<a href="https://sqrtminusone.xyz/"><small>Pavel Korytov, 2021</small></a>
</div>
</div>
</body>
</html>

View file

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html><head>
<meta name="generator" content="Hugo 0.81.0" />
<meta name="generator" content="Hugo 0.87.0" />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
@ -12,7 +12,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
@ -45,6 +45,13 @@
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>
@ -54,8 +61,7 @@
<div id="content">
<div class="container">
<h2 id="about">About</h2>
<figure class="avatar">
<img src="/logo_sq.png"/>
<figure class="avatar"><img src="/logo_sq.png"/>
</figure>
<p><strong>Pavel Korytov</strong></p>

View file

@ -6,11 +6,11 @@
<description>Recent content in Index on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Sat, 01 May 2021 00:00:00 +0300</lastBuildDate><atom:link href="https://sqrtminusone.xyz/index.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Sat, 01 May 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Replacing Jupyter Notebook with Org Mode</title>
<link>https://sqrtminusone.xyz/posts/2021-05-01-org-python/</link>
<pubDate>Sat, 01 May 2021 00:00:00 +0300</pubDate>
<pubDate>Sat, 01 May 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-05-01-org-python/</guid>
<description>Why? Jupyter Notebook and its successor Jupyter Lab providing an interactive development environment for many programming languages are in lots of ways great pieces of software.
@ -21,7 +21,7 @@ A possibility for change appeared with my discovery of Emacs not so long ago.</d
<item>
<title>Multiple Gmail accounts &amp; labels with Emacs</title>
<link>https://sqrtminusone.xyz/posts/2021-02-27-gmail/</link>
<pubDate>Sat, 27 Feb 2021 00:00:00 +0300</pubDate>
<pubDate>Sat, 27 Feb 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-02-27-gmail/</guid>
<description>Intro For quite some time, e-mail seemed like an anomaly in my workflow. I am a long time Gmail user, and my decade-old account has a somewhat formidable quantity of labels and filters. My messages are often assigned multiple labels, and I also like to keep only a bunch of messages in the inbox.
@ -31,7 +31,7 @@ Although, in my opinion, Gmail web UI was and still is leagues ahead of many of
<item>
<title>Hello, world!</title>
<link>https://sqrtminusone.xyz/posts/hello-world/</link>
<pubDate>Mon, 01 Feb 2021 00:00:00 +0300</pubDate>
<pubDate>Mon, 01 Feb 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/hello-world/</guid>
<description>Hello, world! Eventually, there will be something interesting here. Or not.

BIN
public/ox-hugo/all.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View file

@ -11,7 +11,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
@ -43,6 +43,13 @@
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>
@ -57,12 +64,10 @@
<p>Any classical IMAP/SMTP client is hard to use in my case, because a message with multiple labels is copied to IMAP folders for each of the label plus the inbox folder, and the copies look like different messages from the client-side. For example, a message can be read in one label and unread in another.</p>
<p>For a few years, my solution was <a href="https://getmailspring.com/">Mailspring</a>, which provides first-class support for labels. However, it has a feature to deploy <a href="https://www.bbc.com/news/technology-56071437">spy pixels</a> on emails (and offers no protection from them, obviously), the client is Electron-based with a mouse-driven interface, and the sync engine was closed-source at the time.</p>
<p>So, I found an alternative in Emacs+notmuch+lieer and ditched one more proprietary app (the last big one I can&rsquo;t let go of is DataGrip).</p>
<figure>
<img src="/ox-hugo/main.png"/>
<figure><img src="/ox-hugo/main.png"/>
</figure>
<figure>
<img src="/ox-hugo/mail.png"/>
<figure><img src="/ox-hugo/mail.png"/>
</figure>
<p>Notmuch&rsquo;s tags are just as advanced as Gmail&rsquo;s labels, so I have basically the same mail structure accessible from Emacs, Gmail Android client and even the web UI when I don&rsquo;t have access to the first two.</p>
@ -76,7 +81,7 @@
<h3 id="lieer">lieer</h3>
<p><a href="https://github.com/gauteh/lieer">lieer</a> (formerly gmailieer) is a program that uses Gmail API to download email and synchronize Gmail labels with notmuch tags. Because of its usage of Gmail API instead of IMAP, there are no problems with duplicating emails in different labels, etc.</p>
<p>As I need to use multiple versions of Python &amp; Node.js for other reasons, I manage my installations of them with <a href="https://anaconda.org">Anaconda</a> (Miniconda, to be precise). You may instead use <a href="https://docs.python.org/3/library/venv.html">venv</a> or even the system-wide installation of Python and omit the <code>conda</code> clauses, but in my experience Anaconda makes life easier in that regard.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e"># Create an environment with the name &#34;mail&#34;</span>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e"># Create an environment with the name &#34;mail&#34;</span>
conda create --name mail
<span style="color:#75715e"># Activate the environment</span>
conda activate mail
@ -87,12 +92,12 @@ git clone https://github.com/gauteh/lieer.git
cd lieer
pip install .
</code></pre></div><p>After which we may check if the <code>gmi</code> executable is available:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">which gmi
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">which gmi
</code></pre></div><h3 id="notmuch">Notmuch</h3>
<p><a href="https://notmuchmail.org/">Notmuch</a> is present in most of the package repositories, so you can install it with your package manager, which is <code>pacman</code> in my case.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">sudo pacman -S notmuch
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">sudo pacman -S notmuch
</code></pre></div><p>After the installation, run <code>notmuch setup</code>. That will inquire the parameters and create the <code>.notmuch-config</code> file with the answers.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">Your full name <span style="color:#f92672">[</span>Pavel<span style="color:#f92672">]</span>: Pavel Korytov
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">Your full name <span style="color:#f92672">[</span>Pavel<span style="color:#f92672">]</span>: Pavel Korytov
Your primary email address <span style="color:#f92672">[</span>pavel@pdsk.<span style="color:#f92672">(</span>none<span style="color:#f92672">)]</span>: thexcloud@gmail.com
Additional email address <span style="color:#f92672">[</span>Press <span style="color:#e6db74">&#39;Enter&#39;</span> <span style="color:#66d9ef">if</span> none<span style="color:#f92672">]</span>:
Top-level directory of your email archive <span style="color:#f92672">[</span>/home/pavel/mail<span style="color:#f92672">]</span>: /home/pavel/Mail
@ -100,18 +105,18 @@ Tags to apply to all new messages <span style="color:#f92672">(</span>separated
Tags to exclude when searching messages <span style="color:#f92672">(</span>separated by spaces<span style="color:#f92672">)</span> <span style="color:#f92672">[</span>deleted spam<span style="color:#f92672">]</span>:
</code></pre></div><p>It is important to set the <code>new</code> tag for the new messages instead of the default <code>unread</code> and <code>inbox</code>.</p>
<p>Next, add the rule to ignore JSON files to the <code>[new]</code> section of the <code>.notmuch-config</code> file, so it would look like this:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#f92672">[</span>new<span style="color:#f92672">]</span>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#f92672">[</span>new<span style="color:#f92672">]</span>
tags<span style="color:#f92672">=</span>new
ignore<span style="color:#f92672">=</span>/.*<span style="color:#f92672">[</span>.<span style="color:#f92672">](</span>json|lock|bak<span style="color:#f92672">)</span>$/
</code></pre></div><p>That is needed to ignore the lieer config files. Although, as I have noticed, notmuch is generally pretty good at detecting wrong files in its directories, an explicit ignore rule won&rsquo;t hurt.</p>
<p>Now, create the mail directory and run the <a href="https://notmuchmail.org/manpages/notmuch-new-1/">notmuch new</a> command. As notmuch has probably already noticed you, it uses the <a href="https://en.wikipedia.org/wiki/Maildir">maildir</a> format, which basically means that one message is stored in one file.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e"># The same directory mentioned in the 4th question</span>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e"># The same directory mentioned in the 4th question</span>
mkdir ~/Mail
<span style="color:#75715e"># Initialize notmuch</span>
notmuch new
</code></pre></div><h3 id="add-an-account">Add an account</h3>
<p>After that, we can create a directory for a mail account and initialize lieer.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">cd ~/Mail
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">cd ~/Mail
<span style="color:#75715e"># Use whatever name you want</span>
mkdir thexcloud
cd thexcloud
@ -119,14 +124,14 @@ cd thexcloud
gmi init thexcloud@gmail.com
</code></pre></div><p>Running <code>gmi init</code> will run an OAuth authentication to your Gmail account. The credentials will be stored in <code>.credentials.gmailieer.json</code> file, so make sure not to expose it somewhere.</p>
<p>We also can add a few settings for lieer, which will make life easier. First, dots seem to be less awkward to type than slashes for the nested tags:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">gmi set --replace-slash-with-dot
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">gmi set --replace-slash-with-dot
</code></pre></div><p>Then, we don&rsquo;t want the <code>new</code> tag to be pushed back to Gmail</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">gmi set --ignore-tags-local new
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">gmi set --ignore-tags-local new
</code></pre></div><p>Now we can finally download the mail directory. To initiate the download, run</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">gmi sync
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">gmi sync
</code></pre></div><p>The first download can easily take several hours, depending on the size of your email and the speed of your internet connection, but subsequent runs will be much faster.</p>
<p>The last thing to do here is to add the <code>gmi sync</code> command to notmuch&rsquo;s <a href="https://notmuchmail.org/manpages/notmuch-hooks-5/">pre-new hook</a>, so that the email will be synchronized on the <code>notmuch new</code> command.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e"># Create the hooks folder</span>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e"># Create the hooks folder</span>
mkdir -p ~/Mail/.notmuch/hooks
<span style="color:#75715e"># Create the file</span>
cd ~/Mail/.notmuch/hooks
@ -138,7 +143,7 @@ cat &gt; pre-new <span style="color:#e6db74">&lt;&lt;EOF
</span><span style="color:#e6db74">EOF</span>
chmod +x pre-new
</code></pre></div><p>Side note: as a hook for <code>conda</code> tends to be rather slow, I run the <code>gmi</code> command with system-wide Python as follows:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e">#!/bin/bash
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e">#!/bin/bash
</span><span style="color:#75715e"></span>GMI<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/home/pavel/Programs/miniconda3/envs/mail/bin/gmi&#34;</span>
<span style="color:#f92672">(</span>cd /home/pavel/Mail/thexcloud/ <span style="color:#f92672">&amp;&amp;</span> $GMI sync<span style="color:#f92672">)</span>
</code></pre></div><p>Which doesn&rsquo;t seem to cause any particular trouble in that case.</p>
@ -146,7 +151,7 @@ chmod +x pre-new
<p>There are plenty of different <a href="https://notmuchmail.org/frontends/">frontends</a> for notmuch (even GUI apps), but the one I&rsquo;m sticking with the Emacs.</p>
<p>Configuration for Emacs is pretty straightforward, but you probably want to use the notmuch package which came with the system package, because otherwise, you may end up with different versions of frontend and backend.</p>
<p>That&rsquo;s how it can be done with <code>use-package</code>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package notmuch
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package notmuch
:ensure <span style="color:#66d9ef">nil</span>
:commands (notmuch)
:config
@ -159,7 +164,7 @@ chmod +x pre-new
<h3 id="reading-mail">Reading mail</h3>
<p><code>notmuch-search-show-thread</code> (<code>RET</code>) opens the thread under the cursor.</p>
<p><code>notmuch-show-view-part</code> (<code>. v</code> with evil) opens an attachment with associations defined in <a href="https://linux.die.net/man/4/mailcap">.mailcap</a> file. Mine looks like this:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">audio/*; mpc add %s
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">audio/*; mpc add %s
image/*; feh %s
@ -169,7 +174,7 @@ application/postscript ; zathura %s
text/html; /usr/bin/xdg-open %s
</code></pre></div><p>Here watch out for the last line, default version of which may be set as follows:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">text/html; /usr/bin/xdg-open %s ; copiousoutput
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">text/html; /usr/bin/xdg-open %s ; copiousoutput
</code></pre></div><p>Which causes a temporary file to be deleted before it could be opened because recent versions of <code>xdg-open</code> do not block the input.</p>
<p>As expected, Emacs mail reader does not trigger any <a href="https://www.emailprivacytester.com/">spy pixels or other tracking contents of email</a> (not any I know of, at least). However, opening an HTML email in a browser will even run embedded JavaScript. Therefore, <strong>in no case open emails you do not trust with <code>xdg-open</code></strong>. Even if you use NoScript, the browser will still load all the CSS, videos and even iframes, which can be used to track you.</p>
<p>Even Gmail web UI is preferable to view the message in a browser, because the former blocks most of the malicious stuff and does not seem to leak your IP to the sender, for what it&rsquo;s worth.</p>
@ -178,13 +183,13 @@ text/html; /usr/bin/xdg-open %s
<p>After doing so, <code>C-c C-c</code> will run <code>notmuch-mua-send-and-exit</code>, which will invoke the function stated in the <code>message-send-mail-function</code> variable. The default value of the variable is <code>sendmail-query-once</code>, which will inquire the parameters and save them as custom variables.</p>
<p>If SMTP is used, <code>send-mail-function</code> will be set to the one from the built-it <a href="https://www.emacswiki.org/emacs/SendingMail">smtpmail</a> package. SMTP parameters for Gmail are listed <a href="https://support.google.com/mail/answer/7126229?hl=en">here</a>.</p>
<p>Authorization parameters will be saved to your <a href="https://www.emacswiki.org/emacs/GnusAuthinfo">authinfo</a> file. If you didn&rsquo;t have one, the plaintext <code>.authinfo</code> will be created, so it&rsquo;s reasonable to encrypt it:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">cd ~
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">cd ~
gpg -o .authinfo.gpg -c --cipher-algo AES256 .authinfo
</code></pre></div><p>However, if you plan to use multiple accounts with different SMTP servers, it makes more sense to use something like <a href="https://marlam.de/msmtp/msmtp.html">MSMTP</a> to manage multiple accounts. Here are a couple of examples (<a href="https://www.reddit.com/r/emacs/comments/9piml5/a%5Ffew%5Fquick%5Femacsnotmuch%5Fquestions/e83zcck?utm%5Fsource=share&amp;utm%5Fmedium=web2x&amp;context=3">1</a>, <a href="https://www.reddit.com/r/emacs/comments/9piml5/a%5Ffew%5Fquick%5Femacsnotmuch%5Fquestions/e84otah?utm%5Fsource=share&amp;utm%5Fmedium=web2x&amp;context=3">2</a>) how to do that.</p>
<p>Another alternative for Gmail is to use <a href="https://github.com/gauteh/lieer/wiki/GNU-Emacs-and-Lieer">lieer as sendmail program</a>. That may make sense if you don&rsquo;t want to enable IMAP and SMTP on your account.</p>
<p>There are also <a href="https://notmuchmail.org/emacstips/#index13h2">a bunch of ways</a> to set up address completion if the built-in completion based on notmuch database does not suffice.</p>
<p>I also use <a href="https://github.com/mhayashi1120/Emacs-langtool">LanguageTool for Emacs</a> to do a spell checking of important emails (integrations like that really make Emacs shine). For some reason, developers don&rsquo;t give a link to download the server on the frontpage, so <a href="https://dev.languagetool.org/http-server">here it is</a>. And here is the relevant part of my Emacs config:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package langtool
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package langtool
:straight <span style="color:#66d9ef">t</span>
:commands (langtool-check)
:config
@ -195,7 +200,7 @@ gpg -o .authinfo.gpg -c --cipher-algo AES256 .authinfo
<h3 id="adding-an-account">Adding an account</h3>
<p>Now we can send and receive mail from one account. Adding another account is also pretty easy.</p>
<p>If another account is Gmail, the process starts the same as before:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e"># Create a directory</span>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e"># Create a directory</span>
mkdir -p ~/Mail/progin6304
cd ~/Mail/progin6304
<span style="color:#75715e"># OAuth</span>
@ -203,12 +208,12 @@ gmi init progin6304@gmail.com
<span style="color:#75715e"># Settings</span>
gmi set --replace-slash-with-dot
</code></pre></div><p>However, before running <code>gmi sync</code> for the second account, we want to make sure that we can distinguish the message from different accounts. To do that, I add the <code>main</code> for the main account and <code>progin</code> for the second account. We also don&rsquo;t want these labels to be pushed:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">cd ~/Mail/thexcloud
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">cd ~/Mail/thexcloud
gmi set --ignore-tags-local new,mail,progin
cd ~/Mail/progin6304
gmi set --ignore-tags-local new,mail,progin
</code></pre></div><p>Now we can use notmuch&rsquo;s <code>post-new</code> hook to tag the messages based on their folder as follows:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">cd ~/Mail/.notmuch/hooks
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">cd ~/Mail/.notmuch/hooks
cat &gt; post-new <span style="color:#e6db74">&lt;&lt;EOF
</span><span style="color:#e6db74">#!/bin/bash
</span><span style="color:#e6db74">notmuch tag +main &#34;path:thexcloud/** AND tag:new&#34;
@ -218,22 +223,22 @@ cat &gt; post-new <span style="color:#e6db74">&lt;&lt;EOF
chmod +x post-new
</code></pre></div><p>Now it finally makes sense why we wanted to use the <code>new</code> tag in the first place. In principle, any kind of tagging logic can be applied here, but for the reasons I stated earlier, I prefer to set up filters in the Gmail web interface.</p>
<p>The last thing to do is to modify the <code>pre-new</code> hook:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e">#!/bin/bash
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e">#!/bin/bash
</span><span style="color:#75715e"></span>GMI<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/home/pavel/Programs/miniconda3/envs/mail/bin/gmi&#34;</span>
<span style="color:#f92672">(</span>cd /home/pavel/Mail/thexcloud/ <span style="color:#f92672">&amp;&amp;</span> $GMI sync<span style="color:#f92672">)</span>
<span style="color:#f92672">(</span>cd /home/pavel/Mail/progin6304/ <span style="color:#f92672">&amp;&amp;</span> $GMI sync<span style="color:#f92672">)</span>
</code></pre></div><p>After which we can finally tag the existing messages and download ones from the new account</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">notmuch tag +main <span style="color:#e6db74">&#34;path:thexcloud/**&#34;</span>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">notmuch tag +main <span style="color:#e6db74">&#34;path:thexcloud/**&#34;</span>
notmuch new
</code></pre></div><p>The obvious problem, however, is that the messages are fetched sequentially, which is rather slow. A solution is to use something like <a href="http://www.gnu.org/software/parallel/">GNU Parallel</a>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e">#!/bin/bash
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e">#!/bin/bash
</span><span style="color:#75715e"></span>GMI<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/home/pavel/Programs/miniconda3/envs/mail/bin/gmi&#34;</span>
parallel -j0 <span style="color:#e6db74">&#34;(cd /home/pavel/Mail/{}/ &amp;&amp; </span>$GMI<span style="color:#e6db74"> sync)&#34;</span> ::: thexcloud progin6304
</code></pre></div><p>I haven&rsquo;t encountered any trouble with that solution so far (and I don&rsquo;t see anything thread-unsafe in the lieer code), but I&rsquo;ll keep an eye on that.</p>
<p>In principle, it shouldn&rsquo;t be too hard to add a normal IMAP account as well with <a href="https://isync.sourceforge.io/mbsync.html">mbsync</a>, but I expect it would require something like iterating through the directory structure and assigning notmuch labels based on that. I&rsquo;ll probably try that some time in the future.</p>
<h3 id="emacs">Emacs</h3>
<p>With that done, I also want separate entries on the start page for each of the accounts. Doing that is easy enough, just modify the <code>notmuch-saved-searches</code> variable with <code>customize-group</code> or like this:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq notmuch-saved-searches
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq notmuch-saved-searches
<span style="color:#f92672">&#39;</span>((:name <span style="color:#e6db74">&#34;inbox (main)&#34;</span> :query <span style="color:#e6db74">&#34;tag:inbox AND tag:main&#34;</span>)
(:name <span style="color:#e6db74">&#34;unread (main)&#34;</span> :query <span style="color:#e6db74">&#34;tag:unread AND tag:main&#34;</span>)
(:name <span style="color:#e6db74">&#34;sent (main)&#34;</span> :query <span style="color:#e6db74">&#34;tag:sent AND tag:main&#34;</span>)
@ -245,7 +250,7 @@ parallel -j0 <span style="color:#e6db74">&#34;(cd /home/pavel/Mail/{}/ &amp;&amp
(:name <span style="color:#e6db74">&#34;drafts&#34;</span> :query <span style="color:#e6db74">&#34;tag:draft&#34;</span>)))
</code></pre></div><h2 id="notification-for-new-messages">Notification for new messages</h2>
<p>Now, we can send and receive mail, but we also probably want notifications for new emails. To do that, I wrote a simple script:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e">#!/bin/bash
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e">#!/bin/bash
</span><span style="color:#75715e"></span><span style="color:#75715e"># To run notify-send from cron</span>
export DISPLAY<span style="color:#f92672">=</span>:0
<span style="color:#75715e"># A file with last time of sync</span>
@ -278,7 +283,7 @@ ALL_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</sp
<span style="color:#75715e"># Save sync timestamp</span>
echo <span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>date +%s<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span> &gt; $CHECK_FILE
</code></pre></div><p>The script is launched with cron every 5 minutes:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">*/5 * * * * bash /home/pavel/bin/scripts/check-email
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">*/5 * * * * bash /home/pavel/bin/scripts/check-email
</code></pre></div><p>Here&rsquo;s how the notification looks like:
<img src="/ox-hugo/notification.png" alt=""></p>
<h2 id="caveats">Caveats</h2>

View file

@ -11,7 +11,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
@ -43,6 +43,13 @@
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>
@ -51,8 +58,7 @@
<hr>
<div id="content">
<div class="container">
<figure>
<img src="/ox-hugo/screenshot.png"/>
<figure><img src="/ox-hugo/screenshot.png"/>
</figure>
<h2 id="why">Why?</h2>
@ -81,10 +87,10 @@
<h2 id="basic-setup">Basic setup</h2>
<p>The core package to this whole venture is <a href="https://github.com/nnicandro/emacs-jupyter">emacs-jupyter</a> (another notable alternative <a href="https://github.com/millejoh/emacs-ipython-notebook">ein</a>, using which can help with the collaboration problem).</p>
<p>Install it however you install packages in Emacs, here is my preferred way with <code>use-package</code> and <code>straight.el</code>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package jupyter
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package jupyter
:straight <span style="color:#66d9ef">t</span>)
</code></pre></div><p>Then, we have to enable languages for <code>org-babel</code>. Put the following in your org mode config section:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(org-babel-do-load-languages
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(org-babel-do-load-languages
<span style="color:#e6db74">&#39;org-babel-load-languages</span>
<span style="color:#f92672">&#39;</span>((emacs-lisp <span style="color:#f92672">.</span> <span style="color:#66d9ef">t</span>) <span style="color:#75715e">;; Other languages</span>
(shell <span style="color:#f92672">.</span> <span style="color:#66d9ef">t</span>)
@ -92,21 +98,21 @@
(python <span style="color:#f92672">.</span> <span style="color:#66d9ef">t</span>)
(jupyter <span style="color:#f92672">.</span> <span style="color:#66d9ef">t</span>)))
</code></pre></div><p>Now, you should be able to use source blocks with names like <code>jupyter-LANG</code>, e.g. <code>jupyter-python</code>. To use just <code>LANG</code> src blocks, call the following function after <code>org-babel-do-load-languages</code>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(org-babel-jupyter-override-src-block <span style="color:#e6db74">&#34;python&#34;</span>)
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(org-babel-jupyter-override-src-block <span style="color:#e6db74">&#34;python&#34;</span>)
</code></pre></div><p>That overrides the built-in <code>python</code> block with <code>jupyter-python</code>.</p>
<p>If you use <a href="https://github.com/astahlman/ob-async">ob-async</a>, you have to set <code>jupyter-LANG</code> blocks as ignored by this package, because emacs-jupyter has async execution of its own.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq ob-async-no-async-languages-alist <span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;python&#34;</span> <span style="color:#e6db74">&#34;jupyter-python&#34;</span>))
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq ob-async-no-async-languages-alist <span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;python&#34;</span> <span style="color:#e6db74">&#34;jupyter-python&#34;</span>))
</code></pre></div><h2 id="environments">Environments</h2>
<p>So, we&rsquo;ve set up a basic emacs-jupyter configuration.</p>
<p>The catch here is that Jupyter should be available on Emacs startup (at the time of evaluation of the <code>emacs-jupyter</code> package, to be precise). That means, if you are launching Emacs with something like an application launcher, global Python &amp; Jupyter will be used.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> sys
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> sys
sys<span style="color:#f92672">.</span>executable
</code></pre></div><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">/usr/bin/python3
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">/usr/bin/python3
</code></pre></div><p>Which is probably not what we want. To resolve that, we have to make the right Python available at the required time.</p>
<h3 id="anaconda">Anaconda</h3>
<p>If you were using Jupyter Lab or Notebook before, there is a good chance you install it via <a href="https://anaconda.org/">Anaconda</a>. If not, in a nutshell, it is a package &amp; environment manager, which specializes in Python &amp; R, but also supports a whole lot of stuff like Node.js. In my opinion, it is the easiest way to manage multiple Python installations if you don&rsquo;t use some advanced package manager like Guix.</p>
<p>As one may expect, there is an Emacs package called <a href="https://github.com/necaris/conda.el">conda.el</a> to help working with conda environments in Emacs. We have to put it somewhere before the <code>emacs-jupyter</code> package and call <code>conda-env-activate</code>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package conda
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package conda
:straight <span style="color:#66d9ef">t</span>
:config
(setq conda-anaconda-home (<span style="color:#a6e22e">expand-file-name</span> <span style="color:#e6db74">&#34;~/Programs/miniconda3/&#34;</span>))
@ -121,25 +127,25 @@ sys<span style="color:#f92672">.</span>executable
<h3 id="switching-an-environment">Switching an environment</h3>
<p>However, as you will notice rather soon, <code>emacs-jupyter</code> will always use the Python kernel found on startup. So if you switch to a new environment, the code will still be running in the old one, which is not too convenient.</p>
<p>Fortunately, to fix that we have only to force the refresh of Jupyter kernelspecs:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/jupyter-refresh-kernelspecs ()
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/jupyter-refresh-kernelspecs ()
<span style="color:#e6db74">&#34;Refresh Jupyter kernelspecs&#34;</span>
(interactive)
(jupyter-available-kernelspecs <span style="color:#66d9ef">t</span>))
</code></pre></div><p>Calling <code>M-x my/jupyter-refresh-kernelspecs</code> after an environment switch will give you a new kernel. Just keep in mind that a kernelspec seems to be attached to a session, so you&rsquo;d also have to change the session name to get a new kernel.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> sys
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> sys
sys<span style="color:#f92672">.</span>executable
</code></pre></div><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">/home/pavel/Programs/miniconda3/bin/python
</code></pre></div><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(conda-env-activate <span style="color:#e6db74">&#34;ann&#34;</span>)
</code></pre></div><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> sys
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">/home/pavel/Programs/miniconda3/bin/python
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(conda-env-activate <span style="color:#e6db74">&#34;ann&#34;</span>)
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> sys
sys<span style="color:#f92672">.</span>executable
</code></pre></div><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">/home/pavel/Programs/miniconda3/bin/python
</code></pre></div><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(my/jupyter-refresh-kernelspecs)
</code></pre></div><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> sys
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">/home/pavel/Programs/miniconda3/bin/python
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(my/jupyter-refresh-kernelspecs)
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> sys
sys<span style="color:#f92672">.</span>executable
</code></pre></div><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">/home/pavel/Programs/miniconda3/envs/ann/bin/python
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">/home/pavel/Programs/miniconda3/envs/ann/bin/python
</code></pre></div><h2 id="programming">Programming</h2>
<p>To test if everything is working correctly, run <code>M-x jupyter-run-repl</code>, which should give you a REPL with a chosen kernel. If so, we can finally start using Python in org mode.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python :session hello :async yes
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python :session hello :async yes
print(&#39;Hello, world!&#39;)
#+end_src
@ -147,11 +153,11 @@ print(&#39;Hello, world!&#39;)
: Hello, world!
#+end_src
</code></pre></div><p>To avoid repeating similar arguments for the src block, we can set the <code>header-args</code> property at the start of the file:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+PROPERTY: header-args:python :session hello
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+PROPERTY: header-args:python :session hello
#+PROPERTY: header-args:python+ :async yes
</code></pre></div><p>When a kernel is initialized, an associated REPL buffer is also created with a name like <code>*jupyter-repl[python 3.9.2]-hello*</code>.</p>
<p>One advantage of emacs-jupyter over the standard Org source execution is that kernel requests for input are queried through the minibuffer. So, you can run a code like this:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python
name = input(&#39;Name: &#39;)
print(f&#39;Hello, {name}!&#39;)
#+end_src
@ -162,7 +168,7 @@ print(f&#39;Hello, {name}!&#39;)
<h2 id="code-output">Code output</h2>
<h3 id="images">Images</h3>
<p>Image output should work out of the box. Run <code>M-x org-toggle-inline-images</code> (<code>C-c C-x C-v</code>) after the execution to see the image inline.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [1, 4, 2, 3])
@ -172,9 +178,9 @@ pass
#+RESULTS:
[[file:./.ob-jupyter/86b3c5e1bbaee95d62610e1fb9c7e755bf165190.png]]
</code></pre></div><p>There is some room for improvement though. First, you can add the following hook if you don&rsquo;t want to press this awkward keybinding every time:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(add-hook <span style="color:#e6db74">&#39;org-babel-after-execute-hook</span> <span style="color:#e6db74">&#39;org-redisplay-inline-images</span>)
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(add-hook <span style="color:#e6db74">&#39;org-babel-after-execute-hook</span> <span style="color:#e6db74">&#39;org-redisplay-inline-images</span>)
</code></pre></div><p>Second, we may override the image save path like this:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python :file img/hello.png
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python :file img/hello.png
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [1, 4, 2, 3])
@ -185,15 +191,15 @@ pass
[[file:img/hello.png]]
</code></pre></div><p>That can save you a <code>savefig</code> call if the image has to be used somewhere further.</p>
<p>Finally, by default, the image has a transparent background and a ridiculously small size. That can be fixed with some matplotlib settings:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> matplotlib <span style="color:#f92672">as</span> mpl
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> matplotlib <span style="color:#66d9ef">as</span> mpl
mpl<span style="color:#f92672">.</span>rcParams[<span style="color:#e6db74">&#39;figure.dpi&#39;</span>] <span style="color:#f92672">=</span> <span style="color:#ae81ff">200</span>
mpl<span style="color:#f92672">.</span>rcParams[<span style="color:#e6db74">&#39;figure.facecolor&#39;</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;1&#39;</span>
</code></pre></div><p>At the same time, we can set the image width to prevent images from becoming too large. I prefer to do it inside a <code>emacs-lisp</code> code block in the same org file:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq-local org-image-actual-width <span style="color:#f92672">&#39;</span>(<span style="color:#ae81ff">1024</span>))
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq-local org-image-actual-width <span style="color:#f92672">&#39;</span>(<span style="color:#ae81ff">1024</span>))
</code></pre></div><h3 id="basic-tables">Basic tables</h3>
<p>If you are evaluating something like pandas DataFrame, it will be outputted in the HTML format, wrapped in the <code>begin_export</code> block. To view the data in text format, you can set <code>:display plain</code>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python :display plain
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python :display plain
import pandas as pd
pd.DataFrame({&#34;a&#34;: [1, 2], &#34;b&#34;: [3, 4]})
#+end_src
@ -203,7 +209,7 @@ pd.DataFrame({&#34;a&#34;: [1, 2], &#34;b&#34;: [3, 4]})
: 0 1 3
: 1 2 4
</code></pre></div><p>Another solution is to use something like the <a href="https://pypi.org/project/tabulate/">tabulate</a> package:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python
import pandas as pd
import tabulate
df = pd.DataFrame({&#34;a&#34;: [1, 2], &#34;b&#34;: [3, 4]})
@ -217,7 +223,7 @@ print(tabulate.tabulate(df, headers=df.columns, tablefmt=&#34;orgtbl&#34;))
: | 1 | 2 | 4 |
</code></pre></div><h3 id="html-and-other-rich-output">HTML &amp; other rich output</h3>
<p>Yet another solution is to use emacs-jupyter&rsquo;s option <code>:pandoc t</code>, which invokes pandoc to convert HTML, LaTeX, and Markdown to Org. Predictably, this is slower than the options above.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python :pandoc t
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+begin_src python :pandoc t
import pandas as pd
df = pd.DataFrame({&#34;a&#34;: [1, 2], &#34;b&#34;: [3, 4]})
df
@ -232,7 +238,7 @@ df
:END:
</code></pre></div><p>Also, every once in a while I have to view an actual, unconverted HTML in a browser, e.g. when using <a href="https://python-visualization.github.io/folium/">folium</a> or <a href="https://spacy.io/usage/visualizers">displaCy</a>.</p>
<p>To do that, I&rsquo;ve written a small function, which performs <code>xdg-open</code> on the HTML export block under the cursor:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq my/org-view-html-tmp-dir <span style="color:#e6db74">&#34;/tmp/org-html-preview/&#34;</span>)
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq my/org-view-html-tmp-dir <span style="color:#e6db74">&#34;/tmp/org-html-preview/&#34;</span>)
(use-package f
:straight <span style="color:#66d9ef">t</span>)
@ -258,7 +264,7 @@ df
<p>However, there are standalone packages to view dataframes. One I can point out is <a href="https://github.com/man-group/dtale">dtale</a>, which is a Flask + React app designed just for that purpose. It has a rather extensive list of features, including charting, basic statistical instruments, filters, etc. <a href="http://alphatechadmin.pythonanywhere.com/dtale/main/1">Here</a> is an online demo.</p>
<p>The problem here is that it&rsquo;s a browser app, which means it defies one of the purposes of using Org Mode in the first place. What&rsquo;s more, this application is a rather huge one with lots of dependencies, and they have to be installed in the same environment as your project.</p>
<p>So this approach has its pros and cons as well. Example usage is as follows:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> dtale
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> dtale
d <span style="color:#f92672">=</span> dtale<span style="color:#f92672">.</span>show(df)
d<span style="color:#f92672">.</span>open_browser() <span style="color:#75715e"># Or get an URL from d._url</span>
</code></pre></div><p>Another notable alternative is <a href="https://github.com/adamerose/pandasgui">PandasGUI</a>, which, as one can guess, is a GUI (PyQt5) application, although it uses QtWebEngine inside.</p>
@ -271,22 +277,22 @@ d<span style="color:#f92672">.</span>open_browser() <span style="color:#75715e">
</ul>
<h3 id="using-a-remote-kernel">Using a &ldquo;remote&rdquo; kernel</h3>
<p>For the reasons above I sometimes prefer to use a standalone kernel. To start a Jupyter kernel, run the following command in the environment and path you need:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">jupyter kernel --kernel<span style="color:#f92672">=</span>python
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">jupyter kernel --kernel<span style="color:#f92672">=</span>python
</code></pre></div><p>After the kernel is launched, write the path to the connection file into the <code>:session</code> header and press <code>C-c C-c</code> to refresh the setup:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+PROPERTY: header-args:python :session /home/pavel/.local/share/jupyter/runtime/kernel-e770599c-2c98-429b-b9ec-4d1ddf5fc16c.json
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+PROPERTY: header-args:python :session /home/pavel/.local/share/jupyter/runtime/kernel-e770599c-2c98-429b-b9ec-4d1ddf5fc16c.json
</code></pre></div><p>Now python source blocks should be executed in the kernel.</p>
<p>To open a REPL, run <code>M-x jupyter-connect-repl</code> and select the given JSON. Or launch a standalone REPL like this:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">jupyter qtconsole --existing kernel-e770599c-2c98-429b-b9ec-4d1ddf5fc16c.json
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">jupyter qtconsole --existing kernel-e770599c-2c98-429b-b9ec-4d1ddf5fc16c.json
</code></pre></div><p>Executing a piece of code in the REPL allows proper debugging, for instance with <code>%pdb</code> magic. Also, Jupyter QtConsole generally handles large outputs better and even allows certain kinds of rich output in the REPL.</p>
<h3 id="some-automation">Some automation</h3>
<p>Now, I wouldn&rsquo;t use Emacs if it wasn&rsquo;t possible to automate at least some of the listed steps. So here are the functions I&rsquo;ve written for that.</p>
<p>First, we need to get open ports on the system:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/get-open-ports ()
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/get-open-ports ()
(<span style="color:#a6e22e">mapcar</span>
<span style="color:#a6e22e">#&#39;string-to-number</span>
(split-string (shell-command-to-string <span style="color:#e6db74">&#34;ss -tulpnH | awk &#39;{print $5}&#39; | sed -e &#39;s/.*://&#39;&#34;</span>) <span style="color:#e6db74">&#34;\n&#34;</span>)))
</code></pre></div><p>Then, list the available kernel JSONs:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq my/jupyter-runtime-folder (<span style="color:#a6e22e">expand-file-name</span> <span style="color:#e6db74">&#34;~/.local/share/jupyter/runtime&#34;</span>))
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq my/jupyter-runtime-folder (<span style="color:#a6e22e">expand-file-name</span> <span style="color:#e6db74">&#34;~/.local/share/jupyter/runtime&#34;</span>))
(defun my/list-jupyter-kernel-files ()
(<span style="color:#a6e22e">mapcar</span>
@ -295,7 +301,7 @@ d<span style="color:#f92672">.</span>open_browser() <span style="color:#75715e">
(<span style="color:#a6e22e">directory-files-and-attributes</span> my/jupyter-runtime-folder <span style="color:#66d9ef">t</span> <span style="color:#e6db74">&#34;.*kernel.*json$&#34;</span>)
(lambda (x y) (not (<span style="color:#a6e22e">time-less-p</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">6</span> x) (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">6</span> y)))))))
</code></pre></div><p>And query the user for a running kernel:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/select-jupyter-kernel ()
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/select-jupyter-kernel ()
(let ((ports (my/get-open-ports))
(files (my/list-jupyter-kernel-files)))
(<span style="color:#a6e22e">completing-read</span>
@ -305,7 +311,7 @@ d<span style="color:#f92672">.</span>open_browser() <span style="color:#75715e">
(<span style="color:#a6e22e">member</span> (<span style="color:#a6e22e">cdr</span> file) ports))
files))))
</code></pre></div><p>After which we can use the <code>my/select-jupyter-kernel</code> function however we want:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/insert-jupyter-kernel ()
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/insert-jupyter-kernel ()
<span style="color:#e6db74">&#34;Insert a path to an active Jupyter kernel into the buffer&#34;</span>
(interactive)
(<span style="color:#a6e22e">insert</span> (my/select-jupyter-kernel)))
@ -325,7 +331,7 @@ d<span style="color:#f92672">.</span>open_browser() <span style="color:#75715e">
<p>The last one launches Jupyter QtConsole. <code>setsid</code> is required to run the program in a new session, so it won&rsquo;t close together with Emacs.</p>
<h3 id="cleaning-up">Cleaning up</h3>
<p>I&rsquo;ve also noticed that there are JSON files left in the runtime folder whenever the kernel isn&rsquo;t stopped correctly. So here is a cleanup function.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/jupyter-cleanup-kernels ()
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/jupyter-cleanup-kernels ()
(interactive)
(let* ((ports (my/get-open-ports))
(files (my/list-jupyter-kernel-files))
@ -343,15 +349,15 @@ d<span style="color:#f92672">.</span>open_browser() <span style="color:#75715e">
<p>Export to a standalone HTML is an easy way to share the code with someone who doesn&rsquo;t use Emacs, just remember that HTML may not be the only file you&rsquo;d have to share if you have images in the document. Although you may use something like <a href="https://github.com/BitLooter/htmlark">htmlark</a> later to get a proper self-contained HTML.</p>
<p>To do the export, run <code>M-x org-html-export-to-html</code>. It should work out of the box, however, we can improve the output a bit.</p>
<p>First, we can add a custom CSS to the file. I like this one:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+HTML_HEAD: &lt;link rel=&#34;stylesheet&#34; type=&#34;text/css&#34; href=&#34;https://gongzhitaao.org/orgcss/org.css&#34;/&gt;
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+HTML_HEAD: &lt;link rel=&#34;stylesheet&#34; type=&#34;text/css&#34; href=&#34;https://gongzhitaao.org/orgcss/org.css&#34;/&gt;
</code></pre></div><p>To get a syntax highlighting, we need the <code>htmlize</code> package:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package htmlize
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package htmlize
:straight <span style="color:#66d9ef">t</span>
:after ox
:config
(setq org-html-htmlize-output-type <span style="color:#e6db74">&#39;css</span>))
</code></pre></div><p>If you use the <a href="https://github.com/Fanael/rainbow-delimiters">rainbow-delimeters</a> package, as I do, default colors for delimiters may not look good with the light theme. To fix such issues, put an HTML snippet like this in a <code>begin_export html</code> block or a CSS file:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">&lt;<span style="color:#f92672">style</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;text/css&#34;</span>&gt;
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">&lt;<span style="color:#f92672">style</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;text/css&#34;</span>&gt;
.<span style="color:#a6e22e">org-rainbow-delimiters-depth-1</span><span style="color:#f92672">,</span> .<span style="color:#a6e22e">org-rainbow-delimiters-depth-2</span><span style="color:#f92672">,</span> .<span style="color:#a6e22e">org-rainbow-delimiters-depth-3</span><span style="color:#f92672">,</span> .<span style="color:#a6e22e">org-rainbow-delimiters-depth-4</span> {
<span style="color:#66d9ef">color</span>: <span style="color:#66d9ef">black</span>
}
@ -359,7 +365,7 @@ d<span style="color:#f92672">.</span>open_browser() <span style="color:#75715e">
</code></pre></div><h3 id="latex-pdf">LaTeX -&gt; pdf</h3>
<p>Even though I use LaTeX quite extensively, I don&rsquo;t like to add another layer of complexity here and 98% of the time write plain <code>.tex</code> files. LaTeX by itself provides many good options whenever you need to write a document together with some data or source code, contrary to &ldquo;traditional&rdquo; text processors.</p>
<p>Nevertheless, I want to get at least a tolerable pdf from Org, so here is a piece of my config with some inline comments.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/setup-org-latex ()
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/setup-org-latex ()
(setq org-latex-compiler <span style="color:#e6db74">&#34;xelatex&#34;</span>) <span style="color:#75715e">;; Probably not necessary</span>
(setq org-latex-pdf-process <span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;latexmk -outdir=%o %f&#34;</span>)) <span style="color:#75715e">;; Use latexmk</span>
(setq org-latex-listings <span style="color:#e6db74">&#39;minted</span>) <span style="color:#75715e">;; Use minted to highlight source code</span>
@ -388,11 +394,11 @@ d<span style="color:#f92672">.</span>open_browser() <span style="color:#75715e">
(with-eval-after-load <span style="color:#e6db74">&#39;ox-latex</span>
(my/setup-org-latex))
</code></pre></div><p>In the document itself, add the following headers:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+LATEX_CLASS: org-plain-extarticle
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+LATEX_CLASS: org-plain-extarticle
#+LATEX_CLASS_OPTIONS: [a4paper, 14pt]
</code></pre></div><p>14pt size is required by certain state standards of ours for some reason.</p>
<p>After which you can put whatever you want in the preamble with <code>LATEX_HEADER</code>. My workflow with LaTeX is to write a bunch of <code>.sty</code> files beforehand and import the necessary ones in the preamble. <a href="https://github.com/SqrtMinusOne/LaTeX%5Ftemplates">Here</a> is the repo with these files, although quite predictably, it&rsquo;s a mess. At any rate, I have to write something like the following in the target Org file:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+LATEX_HEADER: \usepackage{styles/generalPreamble}
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">#+LATEX_HEADER: \usepackage{styles/generalPreamble}
#+LATEX_HEADER: \usepackage{styles/reportFormat}
#+LATEX_HEADER: \usepackage{styles/mintedSourceCode}
#+LATEX_HEADER: \usepackage{styles/russianLocale}
@ -400,7 +406,7 @@ d<span style="color:#f92672">.</span>open_browser() <span style="color:#75715e">
<h3 id="ipynb">ipynb</h3>
<p>One last export backend I want to mention is <a href="https://github.com/jkitchin/ox-ipynb">ox-ipynb</a>, which allows exporting Org documents to Jupyter notebooks. Sometimes it works, sometimes it doesn&rsquo;t.</p>
<p>Also, the package isn&rsquo;t on MELPA, so you have to install it from the repo directly.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package ox-ipynb
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package ox-ipynb
:straight (:host github :repo <span style="color:#e6db74">&#34;jkitchin/ox-ipynb&#34;</span>)
:after ox)
</code></pre></div><p>To (try to) do export, run <code>M-x ox-ipynb-export-org-file-ipynb-file</code>.</p>

View file

@ -11,7 +11,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
@ -43,6 +43,13 @@
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>
@ -54,8 +61,8 @@
<h2 id="hello-world">Hello, world!</h2>
<p>Eventually, there will be something interesting here. Or not.</p>
<p>Regradless, I&rsquo;ll check if I can write some Python here</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">print</span>(<span style="color:#e6db74">&#34;Hello, world&#34;</span>)
</code></pre></div><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">Hello, world
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">print(<span style="color:#e6db74">&#34;Hello, world&#34;</span>)
</code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">Hello, world
</code></pre></div>
</div>

View file

@ -11,7 +11,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
@ -44,6 +44,13 @@
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>

View file

@ -6,11 +6,11 @@
<description>Recent content in Posts on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Sat, 01 May 2021 00:00:00 +0300</lastBuildDate><atom:link href="https://sqrtminusone.xyz/posts/index.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Sat, 01 May 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/posts/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Replacing Jupyter Notebook with Org Mode</title>
<link>https://sqrtminusone.xyz/posts/2021-05-01-org-python/</link>
<pubDate>Sat, 01 May 2021 00:00:00 +0300</pubDate>
<pubDate>Sat, 01 May 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-05-01-org-python/</guid>
<description>Why? Jupyter Notebook and its successor Jupyter Lab providing an interactive development environment for many programming languages are in lots of ways great pieces of software.
@ -21,7 +21,7 @@ A possibility for change appeared with my discovery of Emacs not so long ago.</d
<item>
<title>Multiple Gmail accounts &amp; labels with Emacs</title>
<link>https://sqrtminusone.xyz/posts/2021-02-27-gmail/</link>
<pubDate>Sat, 27 Feb 2021 00:00:00 +0300</pubDate>
<pubDate>Sat, 27 Feb 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-02-27-gmail/</guid>
<description>Intro For quite some time, e-mail seemed like an anomaly in my workflow. I am a long time Gmail user, and my decade-old account has a somewhat formidable quantity of labels and filters. My messages are often assigned multiple labels, and I also like to keep only a bunch of messages in the inbox.
@ -31,7 +31,7 @@ Although, in my opinion, Gmail web UI was and still is leagues ahead of many of
<item>
<title>Hello, world!</title>
<link>https://sqrtminusone.xyz/posts/hello-world/</link>
<pubDate>Mon, 01 Feb 2021 00:00:00 +0300</pubDate>
<pubDate>Mon, 01 Feb 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/hello-world/</guid>
<description>Hello, world! Eventually, there will be something interesting here. Or not.

114
public/sass/researcher.css Normal file
View file

@ -0,0 +1,114 @@
#content a, .nav-link {
color: #dc3545;
text-decoration: none; }
#content a *, .nav-link * {
color: #dc3545; }
#content a:hover, .nav-link:hover {
color: #dc3545;
text-decoration: underline; }
#footer a, .navbar-brand {
color: #222222;
text-decoration: none; }
#footer a *, .navbar-brand * {
color: #222222; }
#footer a:hover, .navbar-brand:hover {
color: #222222;
text-decoration: underline; }
#content table td, #content table th {
border: 1px solid #cccccc;
padding: 6px 12px;
text-align: left; }
* {
color: #222222;
font-family: Inconsolata;
line-height: 1.2; }
.container {
max-width: 750px; }
.navbar-brand {
font-size: 2rem; }
#content p {
margin-bottom: 0.6rem; }
#content h1, #content h2, #content h3, #content h4, #content h5, #content h6 {
font-size: medium;
font-weight: bold;
margin: 1rem 0 0.6rem 0; }
#content h1 {
font-size: 1.8rem; }
#content h2 {
font-size: 1.6rem; }
#content h3 {
font-size: 1.4rem; }
#content h4 {
font-size: 1.2rem; }
#content img {
display: block;
margin: 1rem auto;
max-width: 100%; }
#content .avatar > img {
border-radius: 50%;
float: right;
margin: -8px 0 0 16px;
height: 90px;
width: 90px; }
#content ol {
counter-reset: list;
list-style: none;
padding-left: 2rem; }
#content ol > li:before {
content: "[" counter(list, decimal) "] ";
counter-increment: list; }
#content .container > ol, #content .footnotes > ol {
padding-left: 0; }
#content ul {
list-style: inside;
padding-left: 2rem; }
#content .container > ul, #content .footnotes > ul {
padding-left: 0; }
#content table {
margin: 1rem auto;
width: 100%; }
#content table th {
font-weight: bold; }
#content table tr:nth-child(2n) {
background-color: #f8f8f8; }
#content blockquote {
border-left: 4px solid;
font-style: italic;
margin: 1rem 0;
padding: 8px 8px; }
#content code {
color: #222222;
background-color: #f8f8f8;
border: 1px solid #cccccc;
border-radius: 10%;
padding: 0px 4px;
font-family: Inconsolata !important; }
#content pre code {
all: unset;
font-size: 110%; }
#content .highlight {
margin: 1rem auto; }
#content .highlight > pre {
padding: 8px 8px; }

View file

@ -1 +0,0 @@
#content a,.nav-link{color:#dc3545;text-decoration:none}#content a *,.nav-link *{color:#dc3545}#content a:hover,.nav-link:hover{color:#dc3545;text-decoration:underline}#footer a,.navbar-brand{color:#222;text-decoration:none}#footer a *,.navbar-brand *{color:#222}#footer a:hover,.navbar-brand:hover{color:#222;text-decoration:underline}#content table td,#content table th{border:1px solid #ccc;padding:6px 12px;text-align:left}*{color:#222;font-family:Inconsolata;line-height:1.2}.container{max-width:750px}.navbar-brand{font-size:2rem}#content p{margin-bottom:.6rem}#content h1,#content h2,#content h3,#content h4,#content h5,#content h6{font-size:medium;font-weight:700;margin:1rem 0 .6rem}#content h1{font-size:1.8rem}#content h2{font-size:1.6rem}#content h3{font-size:1.4rem}#content h4{font-size:1.2rem}#content img{display:block;margin:1rem auto;max-width:100%}#content .avatar>img{border-radius:50%;float:right;margin:-8px 0 0 16px;height:90px;width:90px}#content ol{counter-reset:list;list-style:none;padding-left:2rem}#content ol>li:before{content:"[" counter(list,decimal)"] ";counter-increment:list}#content .container>ol,#content .footnotes>ol{padding-left:0}#content ul{list-style:inside;padding-left:2rem}#content .container>ul,#content .footnotes>ul{padding-left:0}#content table{margin:1rem auto;width:100%}#content table th{font-weight:700}#content table tr:nth-child(2n){background-color:#f8f8f8}#content blockquote{border-left:4px solid;font-style:italic;margin:1rem 0;padding:8px}#content code{color:#222;background-color:#f8f8f8;border:1px solid #ccc;border-radius:10%;padding:0 4px}#content pre code{all:unset}#content .highlight{margin:1rem auto}#content .highlight>pre{padding:8px}

View file

@ -3,32 +3,46 @@
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://sqrtminusone.xyz/tags/emacs/</loc>
<lastmod>2021-05-01T00:00:00+03:00</lastmod>
<lastmod>2021-05-01T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/</loc>
<lastmod>2021-05-01T00:00:00+03:00</lastmod>
<lastmod>2021-05-01T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/tags/org/</loc>
<lastmod>2021-05-01T00:00:00+03:00</lastmod>
<lastmod>2021-05-01T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/posts/</loc>
<lastmod>2021-05-01T00:00:00+03:00</lastmod>
<lastmod>2021-05-01T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/posts/2021-05-01-org-python/</loc>
<lastmod>2021-05-01T00:00:00+03:00</lastmod>
<lastmod>2021-05-01T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/tags/</loc>
<lastmod>2021-05-01T00:00:00+03:00</lastmod>
<lastmod>2021-05-01T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/tags/mail/</loc>
<lastmod>2021-02-27T00:00:00+03:00</lastmod>
<lastmod>2021-02-27T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/posts/2021-02-27-gmail/</loc>
<lastmod>2021-02-27T00:00:00+03:00</lastmod>
<lastmod>2021-02-27T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/posts/hello-world/</loc>
<lastmod>2021-02-01T00:00:00+03:00</lastmod>
<lastmod>2021-02-01T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/categories/</loc>
</url><url>
<loc>https://sqrtminusone.xyz/configs/</loc>
</url><url>
<loc>https://sqrtminusone.xyz/configs/console/</loc>
</url><url>
<loc>https://sqrtminusone.xyz/configs/desktop/</loc>
</url><url>
<loc>https://sqrtminusone.xyz/configs/emacs/</loc>
</url><url>
<loc>https://sqrtminusone.xyz/configs/guix/</loc>
</url><url>
<loc>https://sqrtminusone.xyz/configs/mail/</loc>
</url><url>
<loc>https://sqrtminusone.xyz/configs/readme/</loc>
</url>
</urlset>

View file

@ -11,7 +11,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
@ -44,6 +44,13 @@
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>

View file

@ -6,11 +6,11 @@
<description>Recent content in emacs on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Sat, 01 May 2021 00:00:00 +0300</lastBuildDate><atom:link href="https://sqrtminusone.xyz/tags/emacs/index.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Sat, 01 May 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/tags/emacs/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Replacing Jupyter Notebook with Org Mode</title>
<link>https://sqrtminusone.xyz/posts/2021-05-01-org-python/</link>
<pubDate>Sat, 01 May 2021 00:00:00 +0300</pubDate>
<pubDate>Sat, 01 May 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-05-01-org-python/</guid>
<description>Why? Jupyter Notebook and its successor Jupyter Lab providing an interactive development environment for many programming languages are in lots of ways great pieces of software.
@ -21,7 +21,7 @@ A possibility for change appeared with my discovery of Emacs not so long ago.</d
<item>
<title>Multiple Gmail accounts &amp; labels with Emacs</title>
<link>https://sqrtminusone.xyz/posts/2021-02-27-gmail/</link>
<pubDate>Sat, 27 Feb 2021 00:00:00 +0300</pubDate>
<pubDate>Sat, 27 Feb 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-02-27-gmail/</guid>
<description>Intro For quite some time, e-mail seemed like an anomaly in my workflow. I am a long time Gmail user, and my decade-old account has a somewhat formidable quantity of labels and filters. My messages are often assigned multiple labels, and I also like to keep only a bunch of messages in the inbox.

View file

@ -11,7 +11,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
@ -44,6 +44,13 @@
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>

View file

@ -6,11 +6,11 @@
<description>Recent content in Tags on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Sat, 01 May 2021 00:00:00 +0300</lastBuildDate><atom:link href="https://sqrtminusone.xyz/tags/index.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Sat, 01 May 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/tags/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>emacs</title>
<link>https://sqrtminusone.xyz/tags/emacs/</link>
<pubDate>Sat, 01 May 2021 00:00:00 +0300</pubDate>
<pubDate>Sat, 01 May 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/tags/emacs/</guid>
<description></description>
@ -19,7 +19,7 @@
<item>
<title>org</title>
<link>https://sqrtminusone.xyz/tags/org/</link>
<pubDate>Sat, 01 May 2021 00:00:00 +0300</pubDate>
<pubDate>Sat, 01 May 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/tags/org/</guid>
<description></description>
@ -28,7 +28,7 @@
<item>
<title>mail</title>
<link>https://sqrtminusone.xyz/tags/mail/</link>
<pubDate>Sat, 27 Feb 2021 00:00:00 +0300</pubDate>
<pubDate>Sat, 27 Feb 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/tags/mail/</guid>
<description></description>

View file

@ -11,7 +11,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
@ -44,6 +44,13 @@
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>

View file

@ -6,11 +6,11 @@
<description>Recent content in mail on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Sat, 27 Feb 2021 00:00:00 +0300</lastBuildDate><atom:link href="https://sqrtminusone.xyz/tags/mail/index.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Sat, 27 Feb 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/tags/mail/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Multiple Gmail accounts &amp; labels with Emacs</title>
<link>https://sqrtminusone.xyz/posts/2021-02-27-gmail/</link>
<pubDate>Sat, 27 Feb 2021 00:00:00 +0300</pubDate>
<pubDate>Sat, 27 Feb 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-02-27-gmail/</guid>
<description>Intro For quite some time, e-mail seemed like an anomaly in my workflow. I am a long time Gmail user, and my decade-old account has a somewhat formidable quantity of labels and filters. My messages are often assigned multiple labels, and I also like to keep only a bunch of messages in the inbox.

View file

@ -11,7 +11,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="stylesheet" href="/sass/researcher.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
@ -44,6 +44,13 @@
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme">
Configs
</a>
</div>

View file

@ -6,11 +6,11 @@
<description>Recent content in org on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Sat, 01 May 2021 00:00:00 +0300</lastBuildDate><atom:link href="https://sqrtminusone.xyz/tags/org/index.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Sat, 01 May 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/tags/org/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Replacing Jupyter Notebook with Org Mode</title>
<link>https://sqrtminusone.xyz/posts/2021-05-01-org-python/</link>
<pubDate>Sat, 01 May 2021 00:00:00 +0300</pubDate>
<pubDate>Sat, 01 May 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-05-01-org-python/</guid>
<description>Why? Jupyter Notebook and its successor Jupyter Lab providing an interactive development environment for many programming languages are in lots of ways great pieces of software.

View file

@ -0,0 +1,114 @@
#content a, .nav-link {
color: #dc3545;
text-decoration: none; }
#content a *, .nav-link * {
color: #dc3545; }
#content a:hover, .nav-link:hover {
color: #dc3545;
text-decoration: underline; }
#footer a, .navbar-brand {
color: #222222;
text-decoration: none; }
#footer a *, .navbar-brand * {
color: #222222; }
#footer a:hover, .navbar-brand:hover {
color: #222222;
text-decoration: underline; }
#content table td, #content table th {
border: 1px solid #cccccc;
padding: 6px 12px;
text-align: left; }
* {
color: #222222;
font-family: Inconsolata;
line-height: 1.2; }
.container {
max-width: 750px; }
.navbar-brand {
font-size: 2rem; }
#content p {
margin-bottom: 0.6rem; }
#content h1, #content h2, #content h3, #content h4, #content h5, #content h6 {
font-size: medium;
font-weight: bold;
margin: 1rem 0 0.6rem 0; }
#content h1 {
font-size: 1.8rem; }
#content h2 {
font-size: 1.6rem; }
#content h3 {
font-size: 1.4rem; }
#content h4 {
font-size: 1.2rem; }
#content img {
display: block;
margin: 1rem auto;
max-width: 100%; }
#content .avatar > img {
border-radius: 50%;
float: right;
margin: -8px 0 0 16px;
height: 90px;
width: 90px; }
#content ol {
counter-reset: list;
list-style: none;
padding-left: 2rem; }
#content ol > li:before {
content: "[" counter(list, decimal) "] ";
counter-increment: list; }
#content .container > ol, #content .footnotes > ol {
padding-left: 0; }
#content ul {
list-style: inside;
padding-left: 2rem; }
#content .container > ul, #content .footnotes > ul {
padding-left: 0; }
#content table {
margin: 1rem auto;
width: 100%; }
#content table th {
font-weight: bold; }
#content table tr:nth-child(2n) {
background-color: #f8f8f8; }
#content blockquote {
border-left: 4px solid;
font-style: italic;
margin: 1rem 0;
padding: 8px 8px; }
#content code {
color: #222222;
background-color: #f8f8f8;
border: 1px solid #cccccc;
border-radius: 10%;
padding: 0px 4px;
font-family: Inconsolata !important; }
#content pre code {
all: unset;
font-size: 110%; }
#content .highlight {
margin: 1rem auto; }
#content .highlight > pre {
padding: 8px 8px; }

View file

@ -0,0 +1 @@
{"Target":"sass/researcher.css","MediaType":"text/css","Data":{}}

View file

@ -1 +0,0 @@
#content a,.nav-link{color:#dc3545;text-decoration:none}#content a *,.nav-link *{color:#dc3545}#content a:hover,.nav-link:hover{color:#dc3545;text-decoration:underline}#footer a,.navbar-brand{color:#222;text-decoration:none}#footer a *,.navbar-brand *{color:#222}#footer a:hover,.navbar-brand:hover{color:#222;text-decoration:underline}#content table td,#content table th{border:1px solid #ccc;padding:6px 12px;text-align:left}*{color:#222;font-family:Inconsolata;line-height:1.2}.container{max-width:750px}.navbar-brand{font-size:2rem}#content p{margin-bottom:.6rem}#content h1,#content h2,#content h3,#content h4,#content h5,#content h6{font-size:medium;font-weight:700;margin:1rem 0 .6rem}#content h1{font-size:1.8rem}#content h2{font-size:1.6rem}#content h3{font-size:1.4rem}#content h4{font-size:1.2rem}#content img{display:block;margin:1rem auto;max-width:100%}#content .avatar>img{border-radius:50%;float:right;margin:-8px 0 0 16px;height:90px;width:90px}#content ol{counter-reset:list;list-style:none;padding-left:2rem}#content ol>li:before{content:"[" counter(list,decimal)"] ";counter-increment:list}#content .container>ol,#content .footnotes>ol{padding-left:0}#content ul{list-style:inside;padding-left:2rem}#content .container>ul,#content .footnotes>ul{padding-left:0}#content table{margin:1rem auto;width:100%}#content table th{font-weight:700}#content table tr:nth-child(2n){background-color:#f8f8f8}#content blockquote{border-left:4px solid;font-style:italic;margin:1rem 0;padding:8px}#content code{color:#222;background-color:#f8f8f8;border:1px solid #ccc;border-radius:10%;padding:0 4px}#content pre code{all:unset}#content .highlight{margin:1rem auto}#content .highlight>pre{padding:8px}

View file

@ -1 +0,0 @@
{"Target":"sass/researcher.min.css","MediaType":"text/css","Data":{}}