dotfiles
Notes on NixOS, Home Manager, and software in general.
Quickstart:
git clone https://github.com/stephen-huan/nixos-config ~/.config/home-manager
sudo nixos-rebuild switch --flake ~/.config/home-manager
Nix
"Nix" is an ambiguous term that can refer to the Nix programming language, the package manager, the collection of packages Nixpkgs, and the operating system NixOS (at the very least).
These parts are documented in the Nix Reference Manual, the Nixpkgs Manual, the NixOS Manual, a short-form tutorial series called the Nix Pills, and the official documentation nix.dev.
nix (language)
The first layer in the stack is the Nix DSL (or the Nix expression language). The official documentation provides a quick tutorial and the official manual provides a comprehensive reference.
The editor tooling I use is
- lsp: nil (alternative: rnix-lsp)
- formatter: nixpkgs-fmt (alternative: alejandra)
- linter: statix
Despite the relative simplicity of the language ("JSON with functions"), there can still be unusual behavior. Within a few days of playing around with the expression language, I found what I thought was a interpreter bug. I posted it on the Discourse (and filed an issue), which caught the attention of a long-time Nix contributor, which led to increased attention on a few old outstanding issues and finally led to a fix which landed in 2.17. So even very simple languages can have nasty parser bugs!
nix (package manager)
Important paths
/nix/store
: Nix store (built derivations, where everything lives)/nix/var/nix/gcroots
: Roots of the garbage collector/nix/var/nix/profiles
: System profiles/nix/var/nix/profiles/system
: Current system/etc/profiles/per-user/<user>
: User packages~/.local/state/nix/profiles
: User profiles (if using xdg)~/.local/state/nix/profiles/home-manager
: Current Home Manager generation~/.nix-profile
(if not using xdg)
nix (cli)
Here are some quick recipes for common tasks.
-
enter a (bash) shell with a given package
nix-shell -I nixpkgs=$(nixpkgs) -p python3
or, to use the current shell,
nix shell $(nixpkgs)#python3
where the
$(nixpkgs)
syntax is explained in "removing channels and flake registries". -
query list of dependencies of (current) system
nix-store --query --requisites /nix/var/nix/profiles/system
-
in tree format
nix-store --query --tree /nix/var/nix/profiles/system
-
list of things referring to a store path
nix-store --query --referrers <store-path>
-
optimize nix store (dedup)
nix-store --optimise
or
nix store optimise
-
nix-env --delete-generations old # all non-current generations nix-env --delete-generations 14d # generations older than 14 days nix-store --gc
or use
nix-collect-garbage -d
which essentially wraps the abovenix-collect-garbage --delete-old nix-collect-garbage --delete-older-than 14d
There is a difference between running with
sudo
(system) and nosudo
(user); try--dry-run
. -
verify nix store paths are valid (hashes match and it is trusted)
nix store verify --all
-
why does one package depend on another?
nix why-depends $(nixpkgs)#zotero $(nixpkgs)#nss
/nix/store/ihp6sm6xn1q19pblxb968q3cm8x9aimq-zotero-6.0.27 └───/nix/store/mbyn9dp2pf3vfsp82g0a289ldck3xibw-nss-3.90
-
why does my (current) system depend on a package?
nix why-depends /nix/var/nix/profiles/system $(nixpkgs)#nss
/nix/store/7hjlhfzzf4ricswgm1wzvpaac34pwvbm-nixos-system-sora-23.11.20231009.f99e5f0 └───/nix/store/bvsjja2xsx2z68h52wxwcriw9vjjzazb-etc └───/nix/store/6xk1k4kl42qqkds2vrprm0mbp1k2mn0l-user-environment └───/nix/store/baxyh4bqi0amw2pi6gv5c28b6lr75jzb-home-manager-path └───/nix/store/ihp6sm6xn1q19pblxb968q3cm8x9aimq-zotero-6.0.27 └───/nix/store/mbyn9dp2pf3vfsp82g0a289ldck3xibw-nss-3.90
-
pass
--precise
to see more information on each edge/nix/store/7hjlhfzzf4ricswgm1wzvpaac34pwvbm-nixos-system-sora-23.11.20231009.f99e5f0 → /nix/store/bvsjja2xsx2z68h52wxwcriw9vjjzazb-etc → /nix/store/6xk1k4kl42qqkds2vrprm0mbp1k2mn0l-user-environment → /nix/store/baxyh4bqi0amw2pi6gv5c28b6lr75jzb-home-manager-path → /nix/store/ihp6sm6xn1q19pblxb968q3cm8x9aimq-zotero-6.0.27 → /nix/store/mbyn9dp2pf3vfsp82g0a289ldck3xibw-nss-3.90 └───activate: …fsx38qi-setup-etc.pl /nix/store/bvsjja2xsx2z68h52wxwcriw9vjjzazb-etc/etc...if (( _localstatus > … └───etc/profiles/per-user/ikue -> /nix/store/6xk1k4kl42qqkds2vrprm0mbp1k2mn0l-user-environment └───bin/accessdb -> /nix/store/baxyh4bqi0amw2pi6gv5c28b6lr75jzb-home-manager-path/bin/accessdb └───bin/.zotero-wrapped -> /nix/store/ihp6sm6xn1q19pblxb968q3cm8x9aimq-zotero-6.0.27/bin/.zotero-wrapped └───usr/lib/zotero-bin-6.0.27/gmp-clearkey/0.1/libclearkey.so: …sm01mc-nspr-4.35/lib:/nix/store/mbyn9dp2pf3vfsp82g0a289ldck3xibw-nss-3.90/lib:/nix/store/73whsps…
-
and
--all
for all paths, not just the shortest one (or both flags)/nix/store/7hjlhfzzf4ricswgm1wzvpaac34pwvbm-nixos-system-sora-23.11.20231009.f99e5f0 └───/nix/store/bvsjja2xsx2z68h52wxwcriw9vjjzazb-etc ├───/nix/store/6xk1k4kl42qqkds2vrprm0mbp1k2mn0l-user-environment │ └───/nix/store/baxyh4bqi0amw2pi6gv5c28b6lr75jzb-home-manager-path │ ├───/nix/store/ihp6sm6xn1q19pblxb968q3cm8x9aimq-zotero-6.0.27 │ │ └───/nix/store/mbyn9dp2pf3vfsp82g0a289ldck3xibw-nss-3.90 │ └───/nix/store/9qmg4vg8hrs6pbbd4cxjrq4jb8fcyxk7-chromium-117.0.5938.149 │ └───/nix/store/ypas0qsb3ikz6k84bk8q89qjlyr9snk5-chromium-unwrapped-117.0.5938.149 │ └───/nix/store/mbyn9dp2pf3vfsp82g0a289ldck3xibw-nss-3.90 └───/nix/store/hrm25v2z602j1qywsia9x638wv1l41f5-system-units └───/nix/store/3dxhmg5jabmihc14j8m0b1rlaq6p3inq-unit-home-manager-ikue.service └───/nix/store/j6xq61kffmfzqcnhgd32ia13z8yl3hk0-home-manager-generation ├───/nix/store/baxyh4bqi0amw2pi6gv5c28b6lr75jzb-home-manager-path └───/nix/store/fncqlph162dpxh4x4879m2y6zy33fkyf-home-manager-files └───/nix/store/3haw6qx1gmyka60xnrs8mi7d4c81pv6l-hm_fontconfigconf.d10hmfonts.conf └───/nix/store/baxyh4bqi0amw2pi6gv5c28b6lr75jzb-home-manager-path
Nixpkgs
Nixpkgs is the package repository. There are search engines for packages and library functions.
NUR
Like Arch, there is a Nix User Repository with an associated package repository and search engine.
nix-index
nix-index is a nixpkgs search tool. There are also pre-built databases and an auto-run wrapper.
Generate the index with
nix-index --nixpkgs $(nixpkgs)
and search for something with
nix-locate bin/mdbook
mdbook-open-on-gh.out 3,824,576 x /nix/store/7f33s7i9q9qr3l4ahpbpgrqp2icgml0n-mdbook-open-on-gh-2.4.1/bin/mdbook-open-on-gh
mdbook-i18n-helpers.out 4,095,192 x /nix/store/v06r1p7zpy9x6jlfrrssrf6nbqqm64pk-mdbook-i18n-helpers-0.2.4/bin/mdbook-gettext
mdbook-i18n-helpers.out 3,807,080 x /nix/store/v06r1p7zpy9x6jlfrrssrf6nbqqm64pk-mdbook-i18n-helpers-0.2.4/bin/mdbook-i18n-normalize
mdbook-i18n-helpers.out 4,140,880 x /nix/store/v06r1p7zpy9x6jlfrrssrf6nbqqm64pk-mdbook-i18n-helpers-0.2.4/bin/mdbook-xgettext
mdbook-kroki-preprocessor.out 8,566,376 x /nix/store/f5gxdaa8fw43ar0wcrsz5bc52yzsjkr2-mdbook-kroki-preprocessor-0.2.0/bin/mdbook-kroki-preprocessor
mdbook-linkcheck.out 13,164,440 x /nix/store/4kicypw0dc07i1syzv6abnyfzfns6n1m-mdbook-linkcheck-0.7.7/bin/mdbook-linkcheck
mdbook-man.out 3,166,272 x /nix/store/s1rmgghpfxam6f0bf5kb9q8ag2305ld7-mdbook-man-unstable-2022-11-05/bin/mdbook-man
mdbook-mermaid.out 5,643,400 x /nix/store/1z7b8af7j3plzkk6i5p4176i5w839b4j-mdbook-mermaid-0.12.6/bin/mdbook-mermaid
mdbook.out 16,064,552 x /nix/store/44ygcgxpw8q7d7gldihkpbjlxd0181gn-mdbook-0.4.34/bin/mdbook
mdbook-admonish.out 5,479,400 x /nix/store/rnpfm3pk7rhj4f7l0lcy0d91630qwa45-mdbook-admonish-1.12.1/bin/mdbook-admonish
mdbook-d2.out 2,453,072 x /nix/store/jyziwz01h3ykich7wcanyw05rbjk8swc-mdbook-d2-unstable-2023-03-30/bin/mdbook-d2
mdbook-epub.out 9,321,376 x /nix/store/v2q8j9gbbwis37x41w53r4p2a07m6pjz-mdbook-epub-unstable-2022-12-25/bin/mdbook-epub
mdbook-pdf.out 10,520,968 x /nix/store/mr5hz1vbpx9jgc27f29890w4k25p3c7c-mdbook-pdf-0.1.7/bin/mdbook-pdf
mdbook-plantuml.out 6,485,488 x /nix/store/09dvwh1ifpr32bj940xsg5p0w1zshvad-mdbook-plantuml-0.8.0/bin/mdbook-plantuml
mdbook-graphviz.out 4,792,168 x /nix/store/lynyplv8i5yq9kigpl0ibslp6hq6l3sl-mdbook-graphviz-0.1.6/bin/mdbook-graphviz
mdbook-cmdrun.out 3,254,448 x /nix/store/mk8d2xv5kpyznpd4yk8b73q6s0qak1cb-mdbook-cmdrun-unstable-2023-01-10/bin/mdbook-cmdrun
mdbook-pagetoc.out 3,700,888 x /nix/store/c46jrg5bj2yg0cqixraxj0jwhjxipdqv-mdbook-pagetoc-0.1.7/bin/mdbook-pagetoc
mdbook-toc.out 2,347,464 x /nix/store/1jzsc6yvhd0daqnwrk1k14y31xwl0lqm-mdbook-toc-0.14.1/bin/mdbook-toc
mdbook-katex.out 2,630,344 x /nix/store/x961ynwvdnjlxmdvp0d5lzvj2bmqlf32-mdbook-katex-0.5.8/bin/mdbook-katex
mdbook-emojicodes.out 3,890,048 x /nix/store/kic0qqckp1y8jda1g724nldfyn0xyrh8-mdbook-emojicodes-0.3.0/bin/mdbook-emojicodes
store permissions
As recommended by the NixOS Manual, and the Discourse, the permissions on the store should be
sudo chown -R 0:0 /nix
sudo chmod +t /nix
writing derivations
Ultimately almost everything in Nix is a derivation --- a specification for producing outputs given fixed inputs. Indeed, the entire NixOS system can be seen as a single large derivation with many inputs. Writing derivations is a skill developed through trial and error. Here I attempt to document implicit conventions, lessons, common gotcha's, and other tips and tricks for writing derivations.
seeing shared libraries
All provided by binutils
readelf -Ws
,objdump -TC
,nm -gD
.
Show undefined symbols only:
nm -ugD
.
hacking on nixpkgs
Build the NixOS configuration from a nixpkgs fork with
sudo nixos-rebuild test --override-input nixpkgs . --fast
pull requests
For reference, here is a list of pull requests I've submitted to nixpkgs, ordered by submission time.
NixOS
The canonical source of truth is the Nix code.
There is a search engine for options.
testing configuration
I couldn't get
nix-instantiate --eval
to play well with flakes, so I use the following setup.
Although I don't usually use a REPL for most languages (python, julia, e.g.), preferring file-based development, unfortunately I couldn't find a more ergonomic setup than using the REPL.
I wrap nix repl
with a shell script like
#!/run/current-system/sw/bin/sh
nix repl \
--file "$(dirname "$0")/nixos-repl.nix" \
--argstr username "$(whoami)" \
--argstr hostname "$(hostname)" \
--argstr path "/keep$HOME/.config/home-manager"
that loads nixos-repl.nix
placed in the same directory.
{ username, hostname, path }:
let
self = builtins.getFlake path;
nixos = self.nixosConfigurations.${hostname};
in
{
inherit self;
${hostname} = nixos;
${username} = nixos.config.home-manager.users.${username};
inherit (nixos) config pkgs options;
inherit (nixos.pkgs) lib;
}
This can be then used like
nix-repl> <hostname>.config.
and press <tab>
to see completions. :p
can be used to force evaluation.
If I have something I want to inspect over and over again, I use a wrapper of nix eval
nix eval ".#nixosConfigurations.$(hostname)" --apply "$(hostname): $1"
like so.
nixos-eval "<hostname>.config.system.activationScripts.usrbinenv"
updating
Simple script to make sure /boot
is mounted before updating.
#!/run/current-system/sw/bin/sh
if [ ! "$(findmnt /boot)" ]; then
sudo mkdir --parents /boot
sudo mount --onlyonce /dev/nvme0n1p1 /boot
fi
sudo nixos-rebuild switch
nixos-rebuild
has a few possible commands.
switch
: activate and make boot defaultboot
: make boot default but don't activatetest
: activate but don't make boot defaultbuild
: neither activate nor make boot default- the result is a symlink placed in
./result
- the result is a symlink placed in
removing channels and flake registries
Channels and flake registries are unnecessary and a source of impurity as they are unpinned.
In NixOS the following configuration disables channels.
{
nix.channel.enable = false;
}
In Home Manager the following configuration disables flake registries.
{
nix.settings = {
experimental-features = [ "nix-command" "flakes" "repl-flake" ];
flake-registry = "";
use-registries = false;
};
}
Note flake-registry
controls the global
registry
while use-registries
controls user registries.
It is convenient to replace the nixpkgs
reference with the shell script nixpkgs
.
#!/run/current-system/sw/bin/sh
flake="/keep$HOME/.config/home-manager"
# `--impure` as the flake may be dirty and considered unlocked
# error: cannot call 'getFlake' on unlocked flake reference
nix eval --impure --raw \
--expr "(builtins.getFlake \"$flake\").inputs.nixpkgs.outPath"
Then commands like
nix-shell -I nixpkgs=flake:nixpkgs -p python3
nix shell nixpkgs#python3
can be replaced by
nix-shell -I nixpkgs=$(nixpkgs) -p python3
nix shell $(nixpkgs)#python3
which has the advantage of not requiring internet as it uses the NixOS configuration's nixpkgs.
In addition, a dependency lookup like
nix why-depends /nix/var/nix/profiles/system $(nixpkgs)#nss
is more accurate as it uses the same version of the package as the system.
miscellaneous
installing from arch
One can switch from Arch Linux completely "in-place",
i.e. without re-partitioning any drives. This can be done by
prototyping with
kexec to get a
working configuration and then using NIXOS_LUSTRATE
through the
lustrate
mechanism (which will move the old root partition to /old-root
).
After this, it's still possible to get into arch with chroot
, e.g.
sudo chroot /old-root /bin/bash
/bin/pacman -Q
Note that commands need to be fully qualified as $PATH
is still from NixOS.
live boot
Live boot can be done from an Arch live boot (see NixOS Wiki - Change root).
cryptsetup open /dev/nvme0n1p3 cryptlvm
mount /dev/VolumeGroup/root /mnt
mount -o bind /dev /mnt/dev
mount -o bind /proc /mnt/proc
mount -o bind /sys /mnt/sys
chroot /mnt /nix/var/nix/profiles/system/activate
chroot /mnt /run/current-system/sw/bin/bash
/bin/sh
Having /bin/sh
is technically an impurity as applications can reference it
without knowing the exact version. However, it's required to do system()
calls in libc,
so it can't be easily disabled entirely. This can cause
issues with
reproducibility
but progress in fixing this seems to have
stalled.
(see also: NixOS Discourse - Add /bin/bash to avoid unnecessary pain, NixOS Wiki - Command Shell)
I think the cleanest thing to do is to use the
default sandbox shell provided in the default
stdenv,
currently
a statically linked ash shell from busybox.
The reasoning being that if /bin/sh
matches the one used at build-time,
there's less chance of a runtime error due to possible incompatibility.
environment.binsh = "${pkgs.busybox-sandbox-shell}/bin/busybox";
It does warn about changing from bash, but considering it's over 10 years old, it's probably fine now.
/usr/bin/env
Like /bin/sh
, /usr/bin/env
is an
impurity that does not
exist at build time.
Unlike sh
, it can be disabled relatively
easily.
environment.usrbinenv = null;
This can cause issues for unpatched software that
rely on env
, e.g. prettier
installed with npm
.
There are (currently) also a few minor spurious errors that should be fixed, see this issue.
system.activationScripts.usrbinenv =
lib.mkIf (config.environment.usrbinenv == null) (
lib.mkForce ''
rm -f /usr/bin/env
mkdir -p /usr/bin
rmdir --ignore-fail-on-non-empty /usr/bin /usr
''
);
systemd.services.systemd-update-done.serviceConfig.ExecStart = [
"" # clear
(
pkgs.writeShellScript "systemd-update-done-wrapper" ''
mkdir -p /usr
${pkgs.systemd}/lib/systemd/systemd-update-done
rmdir --ignore-fail-on-non-empty /usr
''
)
];
vulnix
vulnix scans the dependencies of the entire system for CVEs.
vulnix --system
Home manager
Home Manager
brings NixOS-like modules to per-user configuration (files in ~
).
If the NixOS module is used, then the home-manager configuration is built along with NixOS.
There is also a search engine for options, not to be confused with NixOS modules/options.
not updating
If one deletes a folder managed by Home Manager,
~/.config/nix/nix.conf
, say, it won't necessarily be regenerated
by sudo nixos-rebuild switch
if the configuration hasn't changed.
A rebuild can be forced with
sudo systemctl restart home-manager-<user>.service
impermanence
impermanence registers
persistent storage for when root gets wiped on reboot (e.g. tmpfs on /
).
See
- https://elis.nu/blog/2020/05/nixos-tmpfs-as-root/
- https://elis.nu/blog/2020/06/nixos-tmpfs-as-home/
- https://grahamc.com/blog/erase-your-darlings/
configuration
Example configurations
- https://gist.github.com/byrongibson/b279469f0d2954cc59b3db59c511a199
- https://github.com/nix-community/impermanence/issues/92
Configuration is relatively simple, change something like
fileSystems."/" = {
device = "/dev/VolumeGroup/root";
fsType = "ext4";
};
to
fileSystems."/" = {
fsType = "tmpfs";
options = [ "defaults" "size=2G" "mode=755" ];
};
fileSystems."/keep" = {
device = "/dev/VolumeGroup/root";
fsType = "ext4";
neededForBoot = true;
};
# https://nixos.wiki/wiki/Filesystems
fileSystems."/nix" = {
device = "/keep/nix";
options = [ "bind" ];
};
Here the name /keep
is arbitrary.
important state
/etc/machine-id
: if not stored, new id (re-)generated on every boot- used by
systemd
/journalctl
in/var/log/journal/<machine-id>
- used by
persisting passwords
Can use
users.users.<name>.password
: (plaintext) passwordusers.users.<name>.hashedPassword
: hashed password frommkpasswd
users.users.<name>.hashedPasswordFile
: path to hashed password
hashedPasswordFile
is a file whose only
line is a hashed password as generated
by mkpasswd
. Unfortunately hashedPassword
and password
overwrite
hashedPasswordFile
, so if the file is deleted, one can get locked out of
their account. The configuration will warn on rebuild, however.
warning: password file ‘’ does not exist
Generate password with yescrypt
hash function, now
default
on archlinux (and for mkpasswd
).
mkpasswd --method=yescrypt "$(pass encryption/tuxedo/password)" > root.yescrypt
See also reddit, impermanence issue #120.
memory used
Can use df
to measure tmpfs memory
usage.
df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 1.6G 0 1.6G 0% /dev
tmpfs 16G 8.0K 16G 1% /dev/shm
tmpfs 7.7G 6.3M 7.7G 1% /run
tmpfs 16G 1.2M 16G 1% /run/wrappers
tmpfs 2.0G 1.6M 2.0G 1% /
/dev/VolumeGroup/root 883G 447G 392G 54% /keep
tmpfs 3.1G 32K 3.1G 1% /run/user/1000
The relevant line is
tmpfs 2.0G 1.6M 2.0G 1% /
Can check what's about to be cleared with
ncdu -x /
(-x
means to not cross filesystem boundaries)
sudo ncdu -x /
will show the contents of /root
, which may not be accessible normally.
running out of memory
Nix builds works in /tmp
(see boot.tmp.useTmpfs
) which can cause
memory issues for large builds.
One can make a shell script called mktmp
#!/run/current-system/sw/bin/sh
# make a persistent /tmp
sudo mkdir -p /keep/tmp
sudo chmod 1777 /keep/tmp
sudo mount --onlyonce --bind /keep/tmp/ /tmp || true
and rmtmp
#!/run/current-system/sw/bin/sh
# remove a persistent /tmp
sudo umount /tmp
sudo chmod --silent -t /keep/tmp
sudo rm -rf /keep/tmp
to make and remove a temporary persisted /tmp
, respectively.
These shell scripts are designed to be idempotent and inverses of each other.
modules
The list of arguments to a module are
config
: option definitions (setting options)lib
: Nixpkg's library functionspkgs
: reference to Nixpkgsoptions
: option declarations (defining options)modulesPath
: path to Nixpkg's NixOS modules
These are documented in NixOS Manual - Writing NixOS Modules.
Using lib
instead of pkgs.lib
can
sometime prevent infinite recursion errors.
Flakes
Flakes are a (currently) experimental feature replacing the
channel
mechanism along with a few other Nix interfaces (default.nix
, shell.nix
).
Reproducibility is achieved by declaring inputs in flake.nix
whose resolved
versions are pinned in flake.lock
, like the package managers for many
programming languages, enabling easy updates of dependencies. In addition,
the project's interface is also declared in flake.nix
, creating a unified
experience for interacting with any Flake project.
packages
Next is advice for specific packages (following the structure of nixpkgs).
cmus
cmus is a terminal based music player. It's lightweight and fast; what more could you ask for? My only complaint is that if you close the window, the music stops playing. One solution is to put it in a tmux server (this has the added benefit of being able to open multiple cmus windows at the same time, because each is a view into the same running process). These days I'm too lazy to start tmux, so I just put a cmus window in a high-number workspace and switch to that workspace on demand.
My friend swears by mpd because of its client-server architecture: that gives the ability to use any client, from curses-based terminal interfaces to integration in emacs. It also makes it easy to do cool things like fancy frequency visualizations and sharing what music you're listening to on a webserver. I don't have these use cases, so I stick to cmus. And when I tried to setup mpd a long time ago, I found it hard to do and never got it working.
The highest praise I can give is that I have not touched the configuration at all, but I use cmus daily.
pipewire
Make sure the pulseaudio backend is used with :set output_plugin=pulse
.
plugins
The default build supports many different audio formats (cmus --plugins
).
Input Plugins: /nix/store/ndlabjql98bw7yzrdm8cg0yncp0qfg12-cmus-2.10.0/lib/cmus/ip
mad:
Priority: 55
File Types: mp3 mp2
MIME Types: audio/mpeg audio/x-mp3 audio/x-mpeg
cue:
Priority: 50
File Types:
MIME Types: application/x-cue
cdio:
Priority: 50
File Types:
MIME Types: x-content/audio-cdda
wav:
Priority: 50
File Types: wav
MIME Types:
opus:
Priority: 50
File Types: opus
MIME Types:
flac:
Priority: 50
File Types: flac fla
MIME Types:
vorbis:
Priority: 50
File Types: ogg oga ogx
MIME Types: application/ogg audio/x-ogg
mpc:
Priority: 50
File Types: mpc mpp mp+
MIME Types: audio/x-musepack
wavpack:
Priority: 50
File Types: wv
MIME Types: audio/x-wavpack
modplug:
Priority: 50
File Types: mod s3m xm it 669 amf ams dbm dmf dsm far mdl med mtm okt ptm stm ult umx mt2 psm
MIME Types:
mikmod:
Priority: 40
File Types: mod s3m xm it 669 amf dsm far med mtm stm ult
MIME Types:
ffmpeg:
Priority: 30
File Types: aa aac ac3 aif aifc aiff ape au fla flac m4a m4b mka mkv mp+ mp2 mp3 mp4 mpc mpp ogg opus shn tak tta wav webm wma wv
MIME Types:
Output Plugins: /nix/store/ndlabjql98bw7yzrdm8cg0yncp0qfg12-cmus-2.10.0/lib/cmus/op
pulse
alsa
hangs after close
If playing music is paused and then cmus is closed, cmus will hang. Quickly attempting to open another cmus window results in the error message
cmus: Error: an error occured while initializing MPRIS: File exists. MPRIS will be disabled.
cmus: Press <enter> to continue.
MPRIS is the freedesktop specification for music player control, see MPRIS. It's probably a pipewire issue, see Delayed exit from paused music in cmus as well as Quitting while playback is paused takes several seconds which has made a recent recurrence (Cmus hangs when paused for a long time).
usage notes
Playlists
The man pages cmus
and cmus-tutorial
are pretty good, the only complaint
I have is the playlist creation is not well-explained. Press 3
to go to
playlist view, by default this will have only a single playlist called
"default". Create a new playlist with :pl-create playlist-name
(by default
this is not bound to any key so you have to use the command) and delete a
playlist with D
. Playlists are sorted alphabetically but this can probably
be configured somewhere. The asterisk "*" indicates which playlist new songs
will be added to. To change what the active playlist is, press <space>
(this
was the confusing part which I could not find documentation on). Finally, to
add songs press y
on a song (you can also press y
on albums and artists,
which is very useful). To remove the song from the playlist, go to the playlist
view and press D
on the song. To change the order, press p
to move a song
down and P
to move a song up. Finally, to play the playlist press <enter>
and the same controls as usual can be used (x
to play, v
to stop, c
for
play/pause toggle, z
previous song and b
next song).
Note that playing from a playlist switches the mode to "playlist mode"
(this means that there can be two highlights at the same time, one in
playlist view and the other in library view). One can press shift-M
to switch between modes without interrupting the current song.
Queue
The queue is well-explained, I just never knew what it was for. My use case for the queue is if I'm listening to something but I want to hear a particular song, so I can tell cmus to play that song without interrupting the flow of my current listening session. The best way to think of the queue is terms of two concepts: playlists and the implicit queue inherent to cmus.
The "implicit queue" is how I like to think of the "all from library",
"artist from library", and "album from library" modes (toggleable with
m
). If you select "artist from library" and you play an artist, cmus
essentially adds all of that artist's songs to the queue (the "real" queue
which is accessible through pressing 4
is empty, hence the name implicit
queue). Thus, the modes control which song play next, which is what the
queue does. The toggles C
, r
, and s
also control the implicit queue
--- C
toggles "continue", which determines whether the next song is
automatically played or not (if not, then you will have to start the next
song manually). r
toggles "repeat", which determines whether the queue
infinitely cycles, and s
toggles "shuffle", which determines whether the
queue is permuted. Thus, it is helpful to think of the modes and toggles
and manipulating an implicit queue (the modes determine which songs go
into the queue and the toggles determine how that queue behaves).
To go back to the "real" queue, it behaves similarity to a playlist. One
adds songs with e
instead of y
, and the same playlist manipulation can
be done (D
to remove, p
/P
to move around). When cmus determines which
song to play after the current song finishes, it first tries to dequeue a
song from the "real" queue. If the real queue is empty, it dequeues a song
from the implicit queue described above. Thus, if you're listening to an
artist but want to play another song one-off, then you can add that song
to the queue with e
. When the song ends, you'll be back to listening to
that artist in the same position in the implicit queue you were in.
cmus-remote
cmus-remote
can be used to control cmus from the command-line, e.g. to
generate a status text based on the current song (which I do for i3status
)
or to integrate into ranger
, e.g. when selecting an audio file, add the file
to the queue and play it. See the man page cmus-remote
for more details.
sddm
- arch wiki - SDDM
- Install sddm
sudo pacman -S sddm
- Enable sddm
sudo systemctl enable sddm.service
- Default configuration:
/usr/lib/sddm/sddm.conf.d/default.conf
or
sddm --example-config
- Configuration directory:
/etc/sddm.conf.d/
, can place any files in the directory e.g.sddm.conf
, name/extension doesn't matter - Testing
sddm-greeter --test-mode --theme /usr/share/sddm/themes/simplicity
Theming
- Install theme
paru -S simplicity-sddm-theme-git
- or my patch that
fixes an issue where username was empty if real name was not set
- currently merged
- Themes go in
/usr/share/sddm/themes/
by default - Can edit theme settings by copying default theme file
/usr/share/sddm/themes/simplicity/theme.conf
to/usr/share/sddm/themes/simplicity/theme.conf.user
and making custom changes
Profile Icon
- Add a PNG file
username.face.icon
to/usr/share/sddm/faces/
- Or create
~/.face.icon
and let SDDM find it:
setfacl -m u:sddm:x ~/
setfacl -m u:sddm:r ~/.face.icon
neovim
neovim is a fork of vim focused on extensibility and usability. It's an almost drop-in replacement for vim, although there are a few minor differences. Neovim has a few major advantages over vim. In terms of performance, neovim is apparently truly asynchronous, uses the scripting language Lua instead of vimscript with LuaJIT for extra speed, and has a faster startup time. Neovim also has support for syntax-aware syntax highlighting and text formatting (through tree-sitter) as well as built-in support for LSP. In general, neovim is a more modern and extensible replacement for vim and I've found it basically acts as a drop-in replacement without much configuration hassle.
See also Daniel's config for inspiration.
Quickstart
There's at least three ways to configure neovim through Nix.
- NixOS options under
programs.neovim.*
, - Home Manager options also under
programs.neovim.*
, - and NixVim.
The NixOS module only provides basic support for a configuration
file and not much else. Note that the executable nvim
is a
wrapped shell script which can be viewed with nvim $(which nvim)
.
It's therefore possible to have both programs.enable.neovim = true
for
both NixOS and Home Manager as they live in different places, namely,
/run/current-system/sw/bin/nvim
and~/.local/state/nix/profile/bin/nvim
respectively. This means my (hardened) neovim configuration as root (which uses the NixOS system configuration) is different from my personal neovim configuration (which uses the Home Manager user configuration). One advantage is that plugins aren't loaded when running neovim as root.
The Home Manger module provides a few extra conveniences, most notably, plugin
support (programs.neovim.plugins
) which uses neovim's built-in plugin loading
mechanism. This can be slower than modern aggressively optimized plugin
managers which compile configuration and recommend manually managing lazy
loading to delay loading plugins until they're truly necessary. My incredibly
bloated configuration with 34 plugins starts in about ~250ms (at the time of
writing), which is perfectly fine. I'd like to get to 100-150ms which feels
"snappier" to me but objectively speaking, it makes no practical difference.
Finally, NixVim is a module system for configuring neovim. I haven't used it personally since I'm happy with Home Manager and writing Lua, but it's the most "Nix-like" system (clean modules where someone else does the heavy lifting of actually translating Nix declarations into final configuration).
(it was only recently that Nix overtook Lua by lines of code in my configuration!)
Miscellaneous tips
No additional plugin/package managers
Since plugins are automatically installed with neovim, the configuration
is more portable. In addition, packages which should installed with neovim
(language server protocol implementations, formatters, linters, etc.) can
be installed with neovim through programs.neovim.extraPackages
.
Neovim as a man pager
Neovim can be used to read man pages more easily.
export MANPAGER="nvim +Man!"
export MANWIDTH=80
Security-conscious editing
While editing passwords, important emails, or other sensitive information, it's best to have a different configuration so that vim is sandboxed. By default, vim generates swap files, backup files, etc. and will load modelines which have had and continue to have security vulnerabilities.
See my hardened init.lua
-- pass will automatically do some of this, even with no configuration
-- https://git.zx2c4.com/password-store/tree/contrib/vim/redact_pass.vim
vim.opt.shada = ""
vim.opt.history = 0
vim.opt.swapfile = false
vim.opt.backup = false
vim.opt.writebackup = false
vim.opt.undofile = false
vim.opt.secure = true
vim.opt.modeline = false
vim.opt.shelltemp = false
-- save file for all modes
vim.keymap.set({ "", "!" }, "<c-s>", "<cmd>w<cr>")
-- exit file for all modes
vim.keymap.set({ "", "!" }, "<c-q>", "<cmd>q!<cr>")
which can be used with
/run/current-system/sw/bin/nvim --clean --noplugin -n -u init.lua "$@"
Alias this to nvim-private
, which can then be used as an value
for EDITOR
. The commands in init.lua
were based on this
Stack Exchange.
For posterity, here is a vim-compatible version.
" pass will automatically do some of this, even with no configuration
" https://git.zx2c4.com/password-store/tree/contrib/vim/redact_pass.vim
set viminfo=
set history=0
set noswapfile
set nobackup
set nowritebackup
set noundofile
set secure
set nomodeline
set noshelltemp
set nocompatible " turn off vi compatibility mode
set backspace=indent,eol,start " make backspace always work
set showcmd " show an incomplete command
set showmode " show mode
" save file for all modes
noremap <c-s> <cmd>w<cr>
noremap! <c-s> <cmd>w<cr>
" exit file for all modes
noremap <c-q> <cmd>q!<cr>
noremap! <c-q> <cmd>q!<cr>
Reflowing text paragraphs
When editing text in the terminal, it can be helpful for readability to wrap text to a certain line width (traditionally, less than 80 characters long). However, greedily wrapping (neovim's default behavior) can make the edges of paragraphs jagged, which look worse than more rectangular paragraphs.
See my blog post on a simple dynamic programming algorithm that reflows paragraphs "optimally".
In neovim, gq
is the operator and the option 'formatprg'
sets the
program invoked on gq
. I frequently run gqip
(mnemonic: gq
in a
paragraph) while writing. I recommend using my program far
or the
original program it was based on, par.
wine
- arch wiki - wine
- this section will be mainly focused on running visual novels, see eshrh's gist
- also see TheMoeWay - Visual novels on Linux
- need Japanese locale for most games, so generate the locale
- edit
/etc/locale.gen
and uncommentja_JP.UTF-8 UTF-8
, runlocale-gen
locale-gen
- enable the multilib
repository
by uncommenting the right section in
/etc/pacman.conf
[multilib]
Include = /etc/pacman.d/mirrorlist
- install wine
pacman -S wine
- install optional dependencies
- install winetricks (basically a package manger inside wine)
pacman -S winetricks
- install zenity (GUI for winetricks, you could just use the CLI)
pacman -S zenity
wine-mono
for .NET
pacamn -S wine-mono
- if getting an error about
ntlm_auth
when installing things withwinetricks
, install samba
pacman -S samba
- most visual novels are 32-bit, so set
WINEARCH
towin32
set -gx WINEARCH win32
- opt out of microsoft .NET telemetry
set -gx DOTNET_CLI_TELEMETRY_OPTOUT 1
- set windows version to windows XP, sometimes helpful
winecfg
- "Applications" -> "Windows Version:" change to "Windows XP"
extra packages and fonts
- if game doesn't work, try installing more libraries
pacman -S giflib lib32-giflib libpng lib32-libpng libldap lib32-libldap gnutls lib32-gnutls mpg123 lib32-mpg123 openal lib32-openal v4l-utils lib32-v4l-utils libpulse lib32-libpulse libgpg-error lib32-libgpg-error alsa-plugins lib32-alsa-plugins alsa-lib lib32-alsa-lib libjpeg-turbo lib32-libjpeg-turbo sqlite lib32-sqlite libxcomposite lib32-libxcomposite libxinerama lib32-libgcrypt libgcrypt lib32-libxinerama ncurses lib32-ncurses libxslt lib32-libxslt libva lib32-libva gtk3 lib32-gtk3 gst-plugins-base-libs lib32-gst-plugins-base-libs lib32-gst-plugins-good vulkan-icd-loader lib32-vulkan-icd-loader
- if game doesn't work, try installing more libraries with winetricks
winetricks d3dx9 dirac dotnet35 dotnet40 dxvk lavfilters vcrun2003 vcrun2005 vcrun2008
- disable wine DLL overrides
winetricks alldlls=default
- start winetricks
winetricks
- "Select the default wineprefix" -> "Install
a font" -> check
cjkfonts
andcorefonts
running a game
- mount
.iso
as usual, unpack
sudo mount game.iso /mnt
sudo cp -r /mnt/* game/
- run game
LC_ALL="ja_JP.UTF-8" TZ="Asia/Tokyo" wine game.exe
- kill game
wineserver --kill
CDemu
- if error along the lines of "disk not plugged in"
- try restarting
- if that doesn't work, use cdemu
sudo pacman -S cdemu-client cdemu-daemon
- start daemon
cdemu-daemon
- mount iso
cdemu load 0 game.iso
- check mount point
lsblk
- for me, either
/dev/sr0
or/dev/sr1
, check by file size / runlsblk
before loading and after - mount
mount /dev/sr0 /mnt
- add mount point to wine
winecfg
- "Drives" -> "Add...", pick arbitrary letter ("E:" is
typical), change "Path:" or click on "Browse..." to
/mnt
- run game as usual, hopefully just works
ranger
ranger is a terminal file manager. Moving around
and manipulating files with ranger tends to be faster than the equivalent
cd
/ls
/mv
/cp
/rm
/etc. shell commands. For exploring a file system,
ranger is much faster than cd
and ls
since one just presses h
and l
to
go up and down the file hierarchy and always can see the current files. The
operations on files mv
/cp
/rm
/etc. require typing the paths of both the
source and destination, while in ranger one simply acts on the file currently
under the cursor. In general, operations in ranger are faster since the path
does not need to be explicitly specified unlike shell commands in the terminal.
Previews
- Image previews
Edit rc.conf
:
set preview_images true
set preview_images_method ueberzug
preview_images_method
can also be set to w3m
for general terminals.
For the rest of the previews, edit scope.sh
:
- Videos
pacman -S ffmpegthumbnailer
pacman -S pdftoppm
- Syntax highlighting (without
bat
)
Use the package highlight
. To pick a theme, copy the scope via ranger --copy-config=scope
and edit the variable HIGHLIGHT_STYLE
near the top.
To use a base16 theme, replace the highlight command near the bottom.
- Syntax highlighting (with
bat
)
pacman -S bat
mupdf
- has a pdf viewing tool
simulating greyscale/colorblindness
- siam prints in black/white, preview how the document will look
- greyscale: use mupdf,
package
mupdf-tools
mutool draw -c gray -o "output%d.png" input.pdf
- colorblind: use gimp,
package
gimp
redshift
- arch wiki - redshift
- install redshift
pacman -S redshift
- add location to configuration file
~/.config/redshift/redshift.conf
[redshift]
location-provider=manual
[manual]
lat=33.78
lon=-84.39
- can get coordinates with geonames.org
- note: to convert
xxo yy' zz"
to decimal findxx + yy/60 + zz/3600
(hours minutes seconds) - note: north and east are positive, south and west are negative
- can also use google maps, right-click location
- start system service
systemctl --user status redshift.service
sioyek
- sioyek
- relatively new viewer explicitly designed for scientific use (research papers, technical books)
paru -S sioyek
- pretty good, out-of-the-box integration with vimtex
let g:vimtex_view_method = 'sioyek'
zathura
- arch wiki - zathura
- zathura is popular (vim keybinds etc.)
pacman -S zathura
- install specific formats (muPDF backend for PDF), comic book (
.cbz
), etc.
pacman -S zathura-pdf-mupdf
pacman -S zathura-cb
neomutt
neomutt is a mail user agent (MUA). More specifically, it lets you read email from the terminal. It is possible to download and send mail from mutt natively, but I prefer external programs for those functions.
A quick overview:
- downloading mail: offlineimap
- sending mail: msmtp
- reading mail: neomutt + neovim (occasional full-screen reading) + w3m (for html emails)
- editing mail: neovim
- indexing mail: notmuch
- encrypting mail: gpg
- adding attachments: ranger
- determining what program to use to open attachments: rifle
- general selector: fzf
neomutt
neomutt is essentially a superset of regular mutt aiming to fix bugs, collect patches, and in general incite development of mutt. It therefore makes sense to use neomutt rather than mutt.
General notes
My primary email is gmail, which has its quirks. In particular, all emails go into "all mail" (including emails sent by oneself!) and the different "folders" are more like tags --- attributes of the emails in all mail. This mirrors notmuch nicely but IMAP not so much so there will be a few oddities.
I use PGP to sign and encrypt email.
Lastly, I use Google's Advanced Protection program. Surprisingly enough, one can use command-line tools to access mail even with advanced protection on (if you authenticate with OAuth2).
With that in mind, the first step is to get mail.
offlineimap
offlineimap is used to download (and sync!)
mail. Note that this is a two-way operation: it will update the local
repository of mail if there are changes in the remote and it will also
update the remote if there are local changes! There is a risk of deleting
email permanently if you delete locally and have offlineimap sync. Run with
the --dry-run
option to see what offlineimap will do while testing.
offlineimap is configured with Python, unfortunately Python 2. There's a Python 3 fork of offlineimap, and the same author also wrote imapfw, a Python 3 replacement, but the project appears to be dead.
In order to authenticate, we must use OAuth2 as mentioned before. The
specific steps depends on the email provider, but in general we need a
client id, secret, and refresh token. We can redeem the refresh token
for an access token, which is what we actually use to authenticate. I
store these credentials in the lightweight PGP-based password manager
pass. To generate an access token, we could use
offlineimap's built-in oauth2_refresh_token_eval
option but for integration
with msmtp
and caching we might as well use our own program:
offlineimap.py.
Google and Microsoft cover all my email accounts, including those which
that are not necessarily @gmail.com
or @hotmail.com
. For example,
my Georgia Tech email
ending in @gatech.edu
is actually provided by Outlook, so I can use
Microsoft OAuth
to authenticate, without needing to go through
Georgia Tech's single sign-on authentication portal.
Google OAuth
We'll be using the gmail-oauth2-tools repository as the client library.
Follow the instructions here. The Google Cloud Console is pretty poorly designed, so it may take some effort to figure out how to create a new project.
If it initially works but after a week there's the
error KeyError: 'access_token'
it might be that the
refresh token is invalid. This is because Google's OAuth
policy
restricts the lifespan of a refresh token to 7 days if the app is configured
for external users and the publishing setting is "Testing", a common situation
one would be in for personal use. The solution is to press the "PUBLISH APP"
button on the OAuth consent screen. Although it will warn you that "Because
you're using one or more sensitive scopes, your app registration requires
verification by Google. Please prepare your app to submit for verification",
you don't actually need to verify the app, that just removes the warning screen
asking the user whether they trust the developer while getting a refresh token.
Microsoft OAuth
We'll be using the msal client library.
Follow the instructions to create a new application and add IMAP and SMTP permissions. These instructions are a bit verbose, so I'll condense them here:
- Navigate to the Azure portal
- Go to "Azure Active Directory", either by searching or clicking on the icon
- Find "App registrations" in the side bar under "Manage" and press "New registration"
- Under "Manage", select "Authentication". Use the "Web"
platform with a redirect URI of
http://localhost
. - Select "Certificates & secrets" and press "New client secret". Record the client id and secret.
- Select "API Permissions". Press "Add a permission" and use "Microsoft
Graph" with "Delegated permissions". The permissions we need are
offline_access
(under OpenId permissions),User.Read
(under User),IMAP.AccessAsUser.all
(under IMAP) andSMTP.Send
(under SMTP). - Depending on the situation, we might need a tenant. For Georgia Tech,
this is
gtvault.onmicrosoft.com
. This value can be found by going to the "Azure Active Directory" page and looking at the value of "Primary domain". Otherwise, this can be set tocommon
.
Something strange Microsoft does is their refresh tokens:
they give a new refresh token back after every access token request, and
refresh tokens expire after 90 days. If you were authenticating through
offlineimap, you might be passing oauth2_refresh_token
so offlineimap can
automatically request access tokens. So if you suddenly become unable to
request access tokens, it might be because of the refresh token expiration.
offlineimap.py
will automatically save the refreshed refresh token, but
you still need to update the client secrets at least every two years (since
24 months is the longest possible expiration date for client secrets).
msmtp
With offlineimap configured, msmtp works similarly.
Set the authentication protocol to oauthbearer
and passwordeval
to run
the above offlineimap.py
script, passing in the email. That way both
offlineimap
and msmtp
use the same cached access token.
notmuch
notmuch is an email indexer, tagger, and
searcher. Add a postsync hook to offlineimap
so tagging happens on
new mail. We can also use notmuch as an address book by searching the
addresses of previously received emails.
alacritty
I used to use kitty and there really wasn't anything wrong with it. The reason I switched was mainly philosophical, kitty just did too much like the whole integrated tab / window splitting and so on. Terminal emulators should be relatively simple and leave the complexity to other programs (your window manager, tmux, etc.). Alacritty doesn't too much, but has all the features I've come to expect from a terminal emulator. Also, the vim mode is sometimes useful if you really don't want to use the mouse.
See features.md for an overview of supported features.
Bugs
Keybindings Like "$" in Vim Mode Don't Work
The default keybindings that involve shift and non-letter keys don't work. This is an X-specific issue caused by a bug in the upstream library winit's handling of virtual keycodes. See
- github - WindowEvent missing virtual_keycode while DeviceEvent contains it on Linux
- github - WindowEvent missing virtual keycode on Linux
- github - Keybinding doesn't work (Shift + Key4)
To fix, use the scancodes instead of the key
names. Edit ~/.config/alacritty/alacritty.yml
:
key_bindings:
# specify scancode to get around invalid virtual keycode provided by winit
- { key: 5, mods: Shift, mode: Vi|~Search, action: Last }
- { key: 7, mods: Shift, mode: Vi|~Search, action: FirstOccupied }
- { key: 6, mods: Shift, mode: Vi|~Search, action: Bracket }
- { key: 53, mods: Shift, mode: Vi|~Search, action: SearchBackward }
The scancodes can be found with
sudo showkey --keycodes
There is theoretically a difference between interpreted
keycodes and raw scancodes. See arch wiki - keyboard
input for the
details. However, the keycodes shown by showkey --keycodes
seem
to be the same as the ones shown by showkey --scancodes
, both of
which are different than the keycodes or keysyms shown by xev
.
For example, if I press the letter "a" on my keyboard:
showkey --scancodes
: 0x1e (30)showkey --scancodes
: 0x9e (158) is also shownshowkey --keycodes
: 30xev
keycode field: 38xev
keysym field: 0x61 (97), ASCII value for "a"
For Alacritty, you should be using the (decimal) keycode in common between
showkey --scancodes
and showkey --keycodes
. It's possible to get these
from showkey --scancodes
but you have to convert the hex to decimal, and
when I press a key it seems to alternate between two different values.
showkey --keycodes
is easier to use and works.
Cursor Spins on Empty Background
This is especially applicable to i3wm users. The problem is that if the mouse cursor is on the desktop background (not hovering over an active window), then it's stuck in the "spinning" or "waiting" state. For why this happens, see:
The summary is that the freedesktop startup-notification-spec provides a
mechanism by which applications upon launching can signal through X that
they have began started up, and finished starting up. This allows your
cursor to appear "busy" when the application is starting up, and turn back
to normal once the application opens. This also allows i3 to guarantee that
the application's window is put where it was originally launched from.
However, if i3 launches an application with exec
and expects startup
notifications when the application does not send them, then i3 assumes the
application is taking a long time to startup, timing out after 60 seconds,
causing the cursor to appear busy for 60 seconds. This can be fixed by
starting the offending application with exec --no-startup-id
.
Alacritty does not support startup notification events, causing the busy cursor. The default i3 configuration launches a terminal with the following line:
bindsym Mod1+Return exec i3-sensible-terminal
i3-sensible-terminal
, as the name implies, looks for a sensible terminal
in the user's path and since the application is launched with exec
and
not exec --no-startup-id
, the cursor will be busy for 60 seconds after
launching an alacritty window. See:
- github - Alacritty causing 1-2 mins of busy cursor on i3 desktop, and extreme i3 performance issues
- github - Alacritty causing 1-2 mins of busy cursor on i3 desktop (re-opening #868)
The first issue is a nearly 5 year old issue, and the second issue was re-filed by me because new evidence came out that it was in fact Alacritty's noncompliance to startup-notification-spec that causes the issue. Alacritty maintainers refuse to fix this since the issue is (mostly) cosmetic.
Note that the cursor can be fixed immediately by restarting i3.
i3 restart
Improper Spacing on Certain Characters
The characters "★" (Unicode codepoint 0x2605
) and "☆" (0x2606
)
are displayed improperly for "most" monospace fonts. This is because
the Unicode specification considers them single-width characters but
they but are rendered as double-width, causing them to clip into
their neighbors. See the issue I filed, alacritty/alacritty/#6144. I've tested:
- Noto Sans Mono (
noto-fonts
) - IPAGothic (
otf-ipafont
) - Source Code Pro (
adobe-source-code-pro-fonts
)
The fonts which I've found to work has been:
- DejaVu Sans Mono (
ttf-dejavu
)
It's a bit misleading to call this a "bug" since it's pretty much impossible to determine the display width of Unicode characters (it's font specific). That being said, "GUI" programs like Firefox, Signal, and Emacs (but not gvim) seem to have figured it out, so there's no real reason a terminal emulator couldn't.
git
I use git for all of my projects that need version control.
Git credential caching
By default, git will prompt you on every operation that needs authentication to provide a username/password. It is possible to use the built-in storage methods to either cache credentials in memory for 15 minutes, or to store credentials permanently on disk as plaintext. If one wants permanent encrypted credential storage, it requires some additional setup.
See
- git book - 7.14 Git Tools - Credential Storage
- git doc - gitcredentials
- git-credential-manager - Credential stores
The simplest thing to do is to install the git-credential-manager which is developed by GitHub.
paru -S git-credential-manager-core
It's possible to configure git-credential-manger to use the GPG-based password manger pass.
git-credential-manager configure
git config --global credential.credentialStore gpg
or just edit ~/.config/git/config
directly
[credential]
helper = /usr/bin/git-credential-manager
credentialStore = gpg
Next time a credential is requested, a pop-up appears and one can authenticate in a variety of ways (through browser login, through a personal access token, etc.). It then stores the data at
~/.password-store/git/https/github.com/stephen-huan.gpg
for GitHub, for example.
Another program that uses pass
to perform git credential caching is
pass-git-helper, but it
seems a bit more complicated. One advantage of git-credential-manager
is that it is able to use different methods to store its secrets.
git-credential-manager
- git book - 7.14 Git Tools - Credential Storage
- git doc - gitcredentials
- git-credential-manager - Credential stores
- install git-credential-manager
paru -S git-credential-manager-core
- run configuration and use gpg/pass files
git-credential-manager-core configure
git config --global credential.credentialStore gpg
- or edit
~/.config/git/config
directly
[credential]
helper = /usr/share/git-credential-manager-core/git-credential-manager-core
credentialStore = gpg
- running a
git-credential-manager-core
command seems to break arrow keys? - next time credential is requested, pop-up appears, can authenticate in a variety of ways (browser, token, etc.)
- stores at
~/.password-store/git/https/github.com/stephen-huan.gpg
, e.g.
i3
- use
xev
to get keysym names (i.e.[
is bracketleft)
cursor spins on empty background
- see arch wiki - i3
- see i3wm user guide
- see freedesktop.org - startup-notification-spec
- run offending command in i3 config with
exec --no-startup-id
- i3 has startup notifications, i.e. when an application finishes starting, it will signal to i3 that it's finished, i3 will change the cursor from waiting to normal.
- but if the application doesn't support startup notifications, it'll take 1 minute for the cursor to reset to normal
issue in alacritty
- alacritty causes this issue
- see github - Alacritty causing 1-2 mins of busy cursor on i3 desktop, and extreme i3 performance issues
- fix cursor
i3 restart
- alacritty refuses to fix this, see Alacritty causing 1-2 mins of busy cursor on i3 desktop (re-opening #868)
archive
- see reddit - How to get rid of spinning cursor?
- see i3wm faq - What is that thing called --no-startup-id?
- sddm executes
~/.xprofile
by default (check/usr/share/sddm/scripts/Xsession
). - nicer to have single script for all commands in
~/.xprofile
than preface every command withexec
in i3 - (imagined) problem: likely caused by daemons in
~/.xprofile
- seem to have no effect if not directly spawned
by
exec
in i3 config (~/.config/i3/config
)
picom
- arch wiki - picom
- install picom
pacman -S picom
- edit config at
~/.config/picom/picom.conf
- use opengl
# use OpenGL as the rendering backend
backend = "glx";
- screen tears without fading, default fading animation is too slow
# without fading, some screen tears
fading = true;
# speed up default fade speed
fade-delta = 3;
- transparency for aesthetic
# make inactive windows slightly transparent
inactive-opacity = 0.9;
- exclude i3lock from transparency to prevent desktop leaking and exclude floating windows
opacity-rule = [
# exclude screensaver (i3lock) window
"100:class_g = 'i3lock'",
# exclude floating windows
"100:I3_FLOATING_WINDOW@:c",
];
ipafont
- arch wiki - localization/Japanese
- install ipafont from Japan's information-technology promotion agency (IPA)
- "one of the highest quality open source font" - arch wiki
pacman -S otf-ipafont
- see wikipedia - IPA フォント for the differences between IPA[/P/Ex/mj] Mincho/Gothic
fontconfig
fc-list
- query settings
fc-match --verbose sans
- edit
~/.config/fontconfig/fonts.conf
<?xml version="1.0" ?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
<alias>
<family>serif</family>
<prefer>
<family>Noto Serif</family>
<family>IPAMincho</family>
</prefer>
</alias>
<alias>
<family>sans-serif</family>
<prefer>
<family>Noto Sans</family>
<family>IPAGothic</family>
</prefer>
</alias>
<alias>
<family>monospace</family>
<prefer>
<family>Noto Sans Mono</family>
<family>IPAGothic</family>
</prefer>
</alias>
</fontconfig>
japanese
- see ipafont
firefox japanese font is wrong
- differences in kanji for chinese and japanese, e.g. "語" in 日本語, "直" in 直す
- chinese ver., japanese ver.
- firefox displays chinese version despite setting japanese fonts
- enter
about:config
- change
font.cjk_pref_fallback_order
fromzh-cn,zh-hk,zh-tw,ja,ko
toja,zh-cn,zh-hk,zh-tw,ko
- also, default western font is serif instead of sans-serif for some reason, makes japanese also serif, e.g. in myanimelist
- change
font.default.x-western
fromserif
tosans-serif
- or just change in normal settings page
about:preferences
, "General" -> "Fonts" -> "Fonts for" select Latin, "Proportional" select "Sans Serif"
how to tell Noto Sans CJK JP and IPAGothic apart
- katakana "ta": タ
- ipa horizontal line precisely connects the two parallel lines
- noto looks kind of like a ヌ, doesn't touch left and juts past right
pipewire
- arch wiki - PipeWire
- modern drop-in replacement for PulseAudio
- install
pacman -S pipewire
- make sure to select "WirePlumber" session manager
- replace ALSA with pipewire
pacman -S pipewire-alsa
- replace pulseaudio with pipewire
pacman -S pipewire-pulse
- also enables bluetooth management
- enable services
systemctl --user enable pipewire-pulse.service
systemctl --user start pipewire-pulse.service
- check working
pactl info
- speaker test works!
speaker-test
screensaver (xss-lock/i3lock)
- arch wiki - session lock
- arch wiki - power management
- arch wiki - display power management signaling
- install xss-lock
pacman -S xss-lock
- set to use
i3lock
as a locker
xss-lock --transfer-sleep-lock -- i3lock --nofork --image=$HOME/Pictures/config/screensaver &
- for
i3lock
,--nofork
prevents multiple instances and set background image - manually trigger lock
loginctl lock-session
picom transparency leaks screen after lock
- picom set to make inactive windows slightly
transparent (
inactive-opacity = 0.9;
) - this causes
i3lock
to also become transparent, leaking your desktop screen - see reddit - Picom make i3lock opaque
- edit
~/.config/picom/picom.conf
, add
opacity-rule = [ "100:class_g = 'i3lock'" ];
using picom-trans?
man picom
--opacity-rule OPACITY:'CONDITION'
Specify a list of opacity rules, in the format PERCENT:PATTERN, like
50:name *= "Firefox". picom-trans is recommended over this.
- okay,
man picom-trans
, should be ran like
picom-trans -n "i3lock" 100
- however, this has to happen after the window exists
- hard to do, since
i3lock
is should be ran with--nofork
archive
- below simply doesn't work, works when running
i3lock
from a terminal but not when actually triggered (by sleep or withloginctl lock-session
) - follow the instructions for slock in the picom article: arch wiki - picom
- install xwininfo
sudo pacman -S xorg-xwininfo
- run the command and click to get the window id
xwininfo & i3lock --nofork --image=$HOME/Pictures/config/screensaver
- use the discovered id to have picom exclude the window
picom --daemon --focus-exclude 'id = 0x4600007'
alsa-project
- arch wiki - Advanced Linux Sound Architecture
- no need to install, built-in to kernel
- install userspace utilities:
pacman -S alsa-utils
- for better resampling:
pacman -S alsa-plugins
- unmute channels:
alsamixer
- speaker test:
speaker-test -c2
- hard to use, can't get working
- just install userspace component, you'll have to anyways!
bluez
- arch wiki - bluetooth
- arch wiki - bluetooth headset
- install bluez
pacman -S bluez
pacman -S bluez-utils
- enable service
systemctl enable bluetooth.service
systemctl start bluetooth.service
- start command line prompt
bluetoothctl
- turn power on, turn agent, start scanning for devices
[bluetooth]# power on
[bluetooth]# agent on
[bluetooth]# default-agent
[bluetooth]# scan on
- find MAC address of device
- note: might be spammed by other devices, exit to prevent
- pair, connect, and trust for future auto-connect
[bluetooth]# pair MAC_ADDRESS
[bluetooth]# connect MAC_ADDRESS
[bluetooth]# trust MAC_ADDRESS
- enable auto power-on of bluetooth module in
/etc/bluetooth/main.conf
[Policy]
AutoEnable=true
bluetooth randomly stuck
- bluetooth stuck after waking up from sleep
sudo systemctl restart bluetooth.service
and the like hangs- kill daemon directly
sudo pkill -9 bluetoothd
device not showing up
- arch wiki - bluetooth
- certain bluetooth low energy (BLE) devices don't show up in scan
- set
transport le
[bluetooth]# menu scan
[bluetooth]# transport le
[bluetooth]# back
[bluetooth]# scan on
[bluetooth]# devices
- still doesn't work with MM712 mouse, TODO
iwd
- arch wiki - iwd
- install iwd
pacman -S iwd
- edit configuration in
/etc/iwd/main.conf
to enable DHCP management
[General]
EnableNetworkConfiguration=true
- add DNS with openresolv (see DNS)
[Network]
NameResolvingService=resolvconf
- start systemd service
systemctl enable iwd
systemctl start iwd
- enter prompt
iwctl
- helpful commands in prompt
[iwd]# help
[iwd]# station list
[iwd]# station wlan0 connect WIFI_NAME
[iwd]# station list
- still need DNS, can only use systemd-resolved / resolvconf
- it seems iwd can do its own DNS (or DHCP does DNS?)
- DNS is provided by (g)libc, see arch wiki - domain name resolution
eduroam
- generate password hash
iconv -t utf16le | openssl md4 -provider legacy
- EOF to end (don't press enter, sends
'\n'
): pressctrl-D
twice - edit
/var/lib/iwd/essid.8021x
, for eduroam/var/lib/iwd/eduroam.8021x
:
[Security]
EAP-Method=PEAP
EAP-Identity=anonymous@gatech.edu
# EAP-PEAP-CACert=/path/to/root.crt
# EAP-PEAP-ServerDomainMask=lawn.gatech.edu
EAP-PEAP-Phase2-Method=MSCHAPV2
EAP-PEAP-Phase2-Identity=username@gatech.edu
EAP-PEAP-Phase2-Password-Hash=passwordhash
[Settings]
AutoConnect=true
- can't put
EAP-PEAP-CACert
in home directory
ead
- ethernet authentication daemon
systemctl start ead.service
- not sure what this does
- replacement for
wpa_supplicant
, see reddit - EAD ethernet authentication daemon
plymouth
- install plymouth (recommended to use development version, but unstable)
paru -S plymouth
- add plymouth hook to
/etc/mkinitcpio.conf
HOOKS=(base udev autodetect keyboard keymap consolefont modconf block encrypt lvm2 filesystems fsck)
HOOKS=(base udev plymouth autodetect keyboard keymap consolefont modconf block plymouth-encrypt lvm2 filesystems fsck)
- make sure to replace
encrypt
withplymouth-encrypt
!- (now:
plymouth-encrypt
no longer necessary as of version22.02.122-7
)
- (now:
- add
amdgpu
toMODULES
MODULES=(amdgpu ...)
- arch wiki - silent boot
- add kernel parameters:
quiet loglevel=3 udev.log_level=3 splash vt.global_cursor_default=0 fbcon=nodefer
splash
necessary,fbcon=nodefer
: don't try to defer vendor logo- switch display manager service for smoother transition
sudo systemctl disable sddm.service
sudo systemctl enable sddm-plymouth.service
- can't quite get totally smooth transition (goes
to black then sddm) but good enough for me :p
- (now:
plymouth-encrypt
no longer necessary as of version22.02.122-7
)
- (now:
theming
- list themes (can install additional from AUR)
plymouth-set-default-theme -l
- use
-R
to rebuild initramfs
plymouth-set-default-theme -R theme
- or edit
/etc/plymouth/plymouthd.conf
[Daemon]
Theme=simple
- and regenerate initramfs with
sudo mkinitcpio -P
- for themes using ModuleName
two-step
, e.g. spinner (check/usr/share/plymouth/themes/
folder,.plymouth
file for module) - add background to
/usr/share/plymouth/themes/theme/background-tile.png
- can only tile! (seems hardcoded)
script module
- problem: many modules compiled into
.so
, hard to modify - solution: use
script
module, write code in domain-specific language - language documented on Plymouth page but out of date
- easiest to read C source directly
- and examples:
- default script theme
/usr/share/plymouth/themes/script
- spinner script theme
- default script theme
- language is sort of weird
- everything is an object...
- ...except functions, they seem not to be first-class objects
- no runtime errors,
NULL
propagation - global easily pollutes namespace
- feels like what I would imagine JavaScript is
- but to be honest I have written more
.script
than.js
...
- but to be honest I have written more
testing
- switch to virtual console with ctrl+alt+F6
- log in as root, run
plymouthd
plymouth show-splash
plymouth quit
- problem: once plymouth starts showing splash, cannot issue commands!
- solution: make shell file, say
test.fish
plymouthd --debug --debug-file=/usr/share/plymouth/themes/simple/testing/log.txt
plymouth show-splash
sleep 5
plymouth quit
- run with
test.fish
, after 5 seconds automatically kills - testing messages:
plymouthd
plymouth show-splash
set message "test message"
sleep 1
plymouth display-message --text=$message
sleep 2
# has to be the same message or callback isn't called
plymouth hide-message --text=$message
sleep 2
- testing passwords: need to inject key presses into
/dev/tty1
(by default) - easiest way (not necessarily best) with TIOCSTI
- see stackoverflow -
inject.py
:
import fcntl
import sys
import termios
with open(sys.argv[1], "w") as fd:
chars = eval(f"'{sys.argv[2]}'")
for c in chars:
fcntl.ioctl(fd, termios.TIOCSTI, c)
- client script:
plymouthd
plymouth show-splash
sleep 1
plymouth ask-for-password --prompt="test" &
sleep 1
python inject.py /dev/tty1 "these keypresses are sent to /dev/tty1"
sleep 1
# backspaces
python inject.py /dev/tty1 "\x7f\x7f\x7f\x7f\x7f\x7f\x7f"
sleep 1
python inject.py /dev/tty1 "additional text"
sleep 1
# enter, send password
python inject.py /dev/tty1 "\n"
sleep 2
plymouth quit
- useful:
tmux
to have multiple consoles,vim
settings:
set autoindent
set expandtab
set shiftwidth=4
set tabstop=4
set colorcolumn=80
multi-head
careful when scripting:
Window.GetX()
Window.GetY()
are not accurate (leads to black bars on multi-head setups
with different resolutions). Basically assume the Window
's
top left corner is (0, 0)
and everything will be ok.
tuxedo-keyboard
- arch wiki - Tuxedo Pulse 15
- install keyboard control
paru -S tuxedo-keyboard
- install power / CPU / fan control
paru -S tuxedo-control-center-bin
- set screen brightness (0-255)
echo 32 | sudo tee /sys/class/backlight/amdgpu_bl0/brightness
- set keyboard backlight (0-2)
echo 0 | sudo tee /sys/devices/platform/tuxedo_keyboard/leds/white:kbd_backlight/brightness
xorg
xkb
- arch wiki - xmodmap
- outdated, use xkb instead
- still useful for viewing what modifiers are set to, run with
xmodmap
pacman -S xorg-xmodmap
- xev, keyboard event viewer, also useful tool, run with
xev
pacman -S xorg-xev
- arch wiki - X keyboard extension
- install, comes as dependency of
xorg-server
, probably already have it
pacman -S xorg-xkbcomp
- complicated as hell, can't say too much about this
- if you screw up, can make keyboard unusable, first store default config
xkbcomp $DISPLAY output.xkb
- can reset with
setxkbmap -layout us
- once you make custom keymap at
~/.Xkeymap
, put in~/.xprofile
at startup:
test -f ~/.Xkeymap && xkbcomp ~/.Xkeymap $DISPLAY
Super_R as mod3
- use case: qmk
"hyper" (not in the linux
modifier sense) is
ctrl_L + shift_L + alt_L + super_L
- use this as i3 mod,
need secondary modifier that can't be
ctrl/shift/alt/super
- use
super_R
as unusedmod3
to distinguish - comment out (not necessary, no clue what this does)
interpret Super_R+AnyOf(all) {
virtualModifier= Super;
action= SetMods(modifiers=modMapMods,clearLocks);
};
- change
Super
toMod3
here
interpret Super_R+AnyOfOrNone(all) {
action= SetMods(modifiers=Super,clearLocks);
};
- change
Mod4
toMod3
here
modifier_map Mod4 { <RWIN> };
- n.b.: I no longer use this, it's simpler to make
hyper
shift_L + alt_L + super_L
(still unlikely to conflict with other keybindings) and usectrl
as a secondary modifier
pulseaudio
- arch wiki - PulseAudio
- seem to be able to use pulseaudio applications
- e.g. simple mixer
pacman -S pulsemixer
fish
Fish is a non-POSIX compliant shell that can do a lot of interesting things.
See my asciinema for inspiration.
Package manager is fisher although it has its quirks (can only update all packages).
Theme is "Tomorrow", run fish_config
to select it.
playerctl
- arch wiki - MPRIS
- freedesktop - MPRIS D-Bus Interface Specification
- Media Player Remote Interfacing Specification (MPRIS)
- freedesktop specification for music player control
- install playerctl, front-end client to control implementing players
pacman -S playerctl
- start daemon to track most player with most
recent activity, e.g. put in
~/.xprofile
playerctld daemon
XF86Audio
audio control keys are already bound in default i3 config
# Use pactl to adjust volume in PulseAudio.
set $refresh_i3status killall -SIGUSR1 i3status
bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +10% && $refresh_i3status
bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -10% && $refresh_i3status
bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ toggle && $refresh_i3status
bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle && $refresh_i3status
- bind
XF86Audio
player control keys to correspondingplayerctl
commands
# my headphones alternate between play/pause while my keyboard just has play
# so to keep it consistent, force both to toggle
bindsym XF86AudioPlay exec playerctl play-pause
bindsym XF86AudioPause exec playerctl play-pause
bindsym XF86AudioStop exec playerctl stop
bindsym XF86AudioPrev exec playerctl previous
bindsym XF86AudioNext exec playerctl next
bindsym XF86AudioForward exec playerctl position 1+
bindsym XF86AudioRewind exec playerctl position 1-
ibus
- arch wiki - input method
- arch wiki - ibus
- install ibus
pacman -S ibus
- run at startup, set environmental variables, put in
~/.xprofile
ibus-daemon --daemonize --replace --xim
export GTK_IM_MODULE=ibus
export QT_IM_MODULE=ibus
export XMODIFIERS=@im=ibus
- no clue what
--xim
does, but if left out doesn't work in alacritty, e.g. - no clue what the environmental variables do, but if left out doesn't work in alacritty, e.g.
- can put variables in
/etc/environment
but why would you want to? need to edit with sudo, etc. - edit config, add input methods, etc.
ibus-setup
- can also right-click icon if it's running
- change activation shortcut to whatever you like, etc.
mozc (japanese ime)
- see mozc
ibus overwrites xkb
- using xmodmap/xkb to make changes
- ibus randomly clears these when switching back and forth
- "IBus Preferences" -> "Advanced" -> "Keyboard Layout" -> check "Use system keyboard layout"
ibus-mozc
- arch wiki - localization/japanese
- arch wiki - mozc
- open source version of google's japanese input
- install mozc-ut (mozc with much larger UT dictionary)
paru -S mozc
- install communication module with ibus
paru -S ibus-mozc
- add to ibus
ibus-setup
- "IBus Preferences" -> "Input method" -> "Add" -> "Japanese" -> "Mozc"
- startup in hiragana mode, useful if no hardware key for Eisu etc.
- edit
~/.config/mozc/ibus_config.textproto
, changeactive_on_launch
fromFalse
toTrue
...
}
active_on_launch: True
android-tools
- arch wiki - android debug bridge
- install adb
pacman -S android-tools
- install udev rules
pacman -S android-udev
-
enable usb debugging on phone
- e.g., about phone, tap build number 7 times
- system -> developer options -> usb debugging, enable
-
shows up in
adb devices
- copy file from phone
adb pull src dest
- copy file to phone
adb push src dest
clipster
Clipster is a Python clipboard manager that can be installed from the AUR:
paru -S clipster
In order to start it, add the command to your ~/.xprofile
or however you want to run a command on startup.
clipster --daemon &
Clipster supports persistence out of the box and can be configured to store no history.
Edit the configuration file at ~/.config/clipster/clipster.ini
.
[clipster]
# Number of items to save in the history file for each selection.
# 0 - don't save history.
history_size = 0
Note that you can still check your clipboard history with
clipster --select
This will show the entries you've copied, but this data is stored
in memory instead of on disk. If you kill the daemon (pkill clipster
) and re-run it, you'll see that the history is cleared.
GRUB
install
- arch wiki - GRUB
- install grub
sudo pacman -S grub efibootmgr
- Assume EFI system partition already mounted to
/boot
- Install GRUB
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB
- Configuration file at
/etc/default/grub
- Need to run
grub-mkconfig
! - Use
grub-mkconfig
to generate/boot/grub/grub.cfg
grub-mkconfig -o /boot/grub/grub.cfg
- Or can edit
/boot/grub/grub.cfg
directly without/etc/default/grub
microcode
- arch wiki - microcode
- microcode updates
pacman -S amd-ucode
- update GRUB, automatically adds microcode to startup
grub-mkconfig -o /boot/grub/grub.cfg
- check
amd-ucode.img
beforeinitramfs-linux.img
in/boot/grub/grub.cfg
initrd /boot/amd-ucode.img /boot/initramfs-linux.img
- check kernel messages for early loading of microcode
journalctl -k --grep=microcode
image background, styling, theming
- ubuntu - grub
- option 1: set
GRUB_BACKGROUND
in/etc/default/grub
- problem: filesystem encrypted, image not accessible by grub!
- option 2: copy an image file to
/boot/grub
- solution:
/boot
isn't encrypted
- solution:
- colors: set "black" for transparent, full list here
- set
GRUB_COLOR_NORMAL
(default) andGRUB_COLOR_HIGHLIGHT
(selected)
fix rescue shell before menu
- fix initially entering shell instead of menu
- but still works with
exit
command
- but still works with
- re-order UEFI entries
- UEFI NVME Drive BBS Priorities set first to GRUB instead of ubuntu
plocate
plocate is a locate implementation.
Generate the index
sudo updatedb
Look for a path
locate <path>
qmk
- qmk - Setting Up Your QMK Environment
- install qmk
pacman -S qmk
- qmk setup
qmk setup
- or use personal fork
qmk setup stephen-huan/qmk_firmware
- set default keyboard and keymap
qmk config user.keyboard=dm9records/plaid
qmk config user.keymap=stephen-huan
- compile and flash
qmk compile
qmk flash
tmux
tmux is a "terminal multiplexer",
meaning its main functionality is in splitting terminal windows and
controlling multiple terminals from the same window. In practice, I use
it to detach a terminal window from the window itself (e.g. putting
cmus in a tmux server and then
detaching means the music still plays, even if the window is closed.
The music player can then be brought up again with tmux attach
, if
I want to switch songs or adjust the volume). These days I don't make
much use of tmux anymore, instead preferring to use features from my
window manager, terminal emulator, or text editor.
tmux is probably most helpful for remote connections with ssh, so your commands keep running even after you close the connection.
yubikey-manager
- arch wiki - YubiKey
- install manager
pacman -S yubikey-manager
- enable service
systemctl enable pcscd.service
systemctl start pcscd.service
- for U2F
pacman -S libfido2
- with PGP
dhcp (dhclient)
- install dhclient (n.b. deprecated)
pacman -S dhclient
- start system service
systemctl enable dhclient@eno1.service
systemctl start dhclient@eno1.service
- dhclient overwrites
/etc/resolv.conf
which is a problem if using vpn, etc. - see arch forum - dhclient overwrites resolv.conf even when resolvconf is installed
- I can't get this to work, resolvconf processes it in the wrong order
- this could be fixed by hardcoding or just ignoring DNS altogether (I get my DNS server from mullvad or 1.1.1.1 anyways)
- patch from arch forum in
/etc/dhclient-enter-hooks
# if [ -f /etc/resolv.conf ]; then
# chown --reference=/etc/resolv.conf $new_resolv_conf
# chmod --reference=/etc/resolv.conf $new_resolv_conf
# fi
# mv -f $new_resolv_conf /etc/resolv.conf
# use resolvconf
cat $new_resolv_conf | /usr/bin/resolvconf -a $interface
rm $new_resolv_conf
- use unbound to prevent DNS servers being in the wrong order
operation not permitted
- error
journalctl -u dhclient@eno1.service
Jun 11 16:22:03 neko dhclient[687]: send_packet: Operation not permitted
Jun 11 16:22:03 neko dhclient[687]: dhclient.c:2996: Failed to send 300 byte long packet over fallback interface.
- see linuxquestions - dhcpd complains "Failed to send 300 byte long packet over fallback interface."
- when it works check
tcpdump
output (pacman -S tcpdump
)
sudo tcpdump > out.txt
- note that
bootps
is usually port 67 andbootpc
is usually port 68
02:58:43.767759 IP neko.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from b0:25:aa:44:bd:c2 (oui Unknown), length 300
02:58:43.770219 ARP, Request who-has res388d-128-61-95-198.res.gatech.edu (Broadcast) tell _gateway, length 46
02:58:43.773852 IP _gateway.bootps > neko.bootpc: BOOTP/DHCP, Reply, length 300
02:58:43.774738 IP _gateway.bootps > neko.bootpc: BOOTP/DHCP, Reply, length 300
- firewall issue, try using built-in kernel packet filter, front end
iptables
- arch wiki - iptables
- arch wiki - ebtables
- arch wiki - nftables
- open
bootps
andbootpc
ports for DHCP
iptables -A OUTPUT -p udp --sport 1024:65535 --dport 67 -j ACCEPT
iptables -A OUTPUT -p udp --sport 68 --dport 67 -j ACCEPT
iptables -A INPUT -p udp --sport 1024:65535 --dport 68 -j ACCEPT
iptables -A INPUT -p udp --sport 67 --dport 68 -j ACCEPT
- list
ebtables-nft --list
- to undo run
iptables -F
ebtables-nft -F
- firewall created by mullvad
- solution: use split tunnel to exclude dhclient from the vpn, see mullvad - How to use the Mullvad CLI
- edit
/etc/dhclient-exit-hooks
# exclude dhclient from vpn, also from firewall
mullvad split-tunnel pid add "$(pgrep --oldest dhclient)"
dhcpcd
- arch wiki - dhcpcd
- need separate DHCP client for ethernet --- iwd has its own, but only for itself (wireless)
- install dhcpcd
pacman -S dhcpcd
- could enable for all interfaces, but only need for ethernet:
systemctl enable dhcpcd@eno1.service
systemctl start dhcpcd@eno1.service
- hangs on boot up, waiting for IP address
- create
/etc/systemd/system/dhcpcd@eno1.service.d/no-wait.conf
- could use
systemctl edit
[Service]
ExecStart=
ExecStart=/usr/bin/dhcpcd -b -q %I
- already automatically enables/disables ethernet based on cable plug in/out
- add wifi disable/enable based on ethernet state
by adding hook to
/etc/dhcpcd.exit-hook
(or in/etc/dhcpcd.enter-hook
or in/usr/lib/dhcpcd/dhcpcd-hooks
) - based on this comment
- see
man dhcpcd-run-hooks
for the values of$interface
,$reason
, etc.
# disable wifi if ethernet connected and enable wifi if ethernet disconnected
wired=eno1
wireless=wlan0
if [ "${interface}" = $wired ]; then
case "${reason}" in NOCARRIER|BOUND)
if $if_up; then # ethernet up means wifi down
iwctl station $wireless disconnect
elif $if_down; then # ethernet down means wifi up
# parse `iwctl known-networks list` and connect to most recent network
last="$(/home/stephenhuan/bin/iwd-last-network)"
iwctl station $wireless connect $last
fi
;;
esac
fi
losing connection
- connection randomly drops for a few seconds, happens relatively frequently
journalctl -u dhcpcd@eno1.service
May 29 15:17:33 neko dhcpcd[806]: eno1: 00:56:2b:56:19:38(00:00:00:ff:eb:0d) claims 128.61.88.130
May 29 15:17:33 neko dhcpcd[806]: eno1: 00:aa:6e:d4:c0:38(00:00:00:ff:f2:b4) claims 128.61.88.130
May 29 15:17:33 neko dhcpcd[806]: eno1: 10 second defence failed for 128.61.88.130
May 29 15:17:33 neko dhcpcd[806]: eno1: deleting route to 128.61.80.0/20
May 29 15:17:33 neko dhcpcd[806]: eno1: deleting default route via 128.61.80.1
May 29 15:17:34 neko dhcpcd[806]: eno1: rebinding lease of 128.61.88.130
May 29 15:17:34 neko dhcpcd[806]: eno1: probing address 128.61.88.130/20
May 29 15:17:39 neko dhcpcd[806]: eno1: leased 128.61.88.130 for 7200 seconds
May 29 15:17:39 neko dhcpcd[806]: eno1: adding route to 128.61.80.0/20
May 29 15:17:39 neko dhcpcd[806]: eno1: adding default route via 128.61.80.1
- same problem
- advice was to fix the ip conflict, hard to do
- already using dynamic ip instead of static
- can't change the configuration of other devices
- advice was to fix the ip conflict, hard to do
- problem described in rfc2131
- The client receives the DHCPACK message with configuration parameters. The client SHOULD perform a final check on the parameters (e.g., ARP for allocated network address), and notes the duration of the lease specified in the DHCPACK message. At this point, the client is configured. If the client detects that the address is already in use (e.g., through the use of ARP), the client MUST send a DHCPDECLINE message to the server and restarts the configuration process. The client SHOULD wait a minimum of ten seconds before restarting the configuration process to avoid excessive network traffic in case of looping.
- fits with
journalctl
log:- found ip conflict with ARP, someone else is claiming the address
eno1: 00:56:2b:56:19:38(00:00:00:ff:eb:0d) claims 128.61.88.130
- wait for ten seconds before restarting
10 second defence failed for 128.61.88.130
- re-negotiate lease
eno1: leased 128.61.88.130 for 7200 seconds
- check ARP with arp-scan:
pacman -S arp-scan
- solution proposed in issue dhcpcd loses static IP
- certain devices send faulty ARP probes, tell
dhcpcd
to ignore ARP /etc/dhcpcd.conf
noarp
- still might not work
- same issue DHCPCD fails again, with DAD detection this time
- see rfc5227
- as of 2022-06-17 this has not been fixed
- also this error, but probably caused by mullvad
May 31 23:20:37 neko dhcpcd[743]: ps_root_recvmsg: Operation not permitted
globalprotect-openconnect
- if using network manager, install package
networkmanager-openconnect
, unfortunately I am using iwd - can use GlobalProtect-openconnect or gp-saml-gui to do web login
- surprisingly enough, GlobalProtect-openconnect is on official repositories
pacman -S globalprotect-openconnect
- run
gpclient
- enter
vpn.gatech.edu
for portal address - doesn't work with proprietary 2fa
Gateway authentication failed
Unknown response for gateway
prelogin interface.
ifplugd
- arch wiki - network configuration/ethernet
- not necessary if using dhcpcd, same feature works out of the box
- install ifplugd:
pacman -S ifplugd
- edit config to change default
eth0
device toeno1
at/etc/ifplugd/ifplugd.conf
INTERFACES="eno1"
- enable service
systemctl enable ifplugd@eno1.service
systemctl start ifplugd@eno1.service
- can use to disable wifi when ethernet connected and enable wifi when ethernet disconnected
- runs
/etc/ifplugd/ifplugd.action
on up/down with two arguments: name of ethernet interface and whether it went up or down. Shell script inspired by this link:
#!/bin/sh
# disable wifi if ethernet connected and enable wifi if ethernet disconnected
case $2 in
up) # ethernet up means wifi down
iwctl station wlan0 disconnect
;;
down) # ethernet down means wifi up
# parse `iwctl known-networks list` and connect to most recent network
iwctl station wlan0 connect "$(/home/stephenhuan/bin/iwd-last-network)"
;;
esac
- remember to mark as executable!
chmod +x /etc/ifplugd/ifplugd.action
- parsing script
iwd-last-network
simply wrapsiwctl known-networks list
:
#!/usr/bin/env python3
"""
Script to parse `iwctl known-networks list`
and return the most recently connected network.
iwd version 1.30-1.
"""
import datetime
import subprocess
def __known_networks() -> str:
"""Wraps `iwctl known-networks list`."""
out = subprocess.run(
["iwctl", "known-networks", "list"],
capture_output=True,
text=True,
)
return out.stdout
def get_date(date: str) -> datetime.datetime:
"""Parse iwctl date format into a datetime object."""
return datetime.datetime.strptime(date, "%b %d, %H:%M %p")
def get_known_networks() -> list[str]:
"""Parses the output of iwctl."""
lines = __known_networks().strip().splitlines()
header = lines[2].lower()
fields = header.split()[1:]
start = header.find(" ")
starts = {field: header.find(field) - start for field in fields}
offset = {
field: (starts[field], starts.get(next_field, len(header)))
for field, next_field in zip(fields, fields[1:] + [None])
}
get_field = lambda line, field: line[
offset[field][0] + line.find(" ") : offset[field][1] + line.find(" ")
].strip()
return [
(
get_field(row, "name"),
get_field(row, "security"),
get_field(row, "hidden"),
get_date(" ".join(row.split()[-4:])),
)
for row in lines[4:]
]
if __name__ == "__main__":
lines = get_known_networks()
recent = sorted(lines, key=lambda row: row[-1], reverse=True)
print(recent[0][0])
- hang on shutdown:
[ *** ] A stop job is running for ...
- forum post
- bug tracker
- use dhcpcd hook instead?
mullvad
- arch wiki - mullvad
- installing GUI also comes with CLI, nice to have around
- choice of which to install after running below command
paru -S mullvad-vpn
- enable service
systemctl enable mullvad-daemon.service
systemctl start mullvad-daemon.service
- set auto-connect
mullvad auto-connect set on
- running
mullvad-vpn
opens GUI whilemullvad
is CLI - opening GUI creates lock icon in bar, but can't seem to close window
- use i3,
mod+alt+q
- use i3,
- quitting app kills vpn connection
- might be easiest to just use CLI:
- set account number
mullvad account set 1234123412341234
- set protocol to WireGuard
mullvad relay set tunnel-protocol wireguard
- list servers
mullvad relay list
- set server (format 2 character country code, 3 character
city code, server-name), from
mullvad relay list
mullvad relay set location us atl us-atl-001
- can give any prefix, e.g. just
set location us
- connect
mullvad connect
- disconnect
mullvad disconnect
- check status
mullvad status
- external check: am I mullvad?
- launch
<program>
and exclude it from vpn
mullvad-exclude <program>
- or, for currently running process with
<pid>
mullvad split-tunnel pid add <pid>
OpenConnect
- arch wiki - OpenConnect
- install openconnect
pacman -S openconnect
- using global protect, proprietary vpn used on many university campuses
- problem: authentication isn't with SAML, but with some proprietary 2fa
- surprisingly enough, just works, run openconnect
sudo openconnect --protocol=gp vpn.gatech.edu
- have to paste in password with ctrl-shift-V
- make sure mullvad is disconnected before
- automate login with fish script
function vpn --description "connect to gatech's proprietary global protect vpn"
# disconnect mullvad before continuing
set -g mullvad_status (mullvad status)
mullvad disconnect
set password "$(pass school/gatech/gatech.edu | head --lines=1)"
# 1st line is password, 2nd line is 2fa prompt, and 3rd line is gateway
echo -e "$password\\npush1\\ndc-ext-gw.vpn.gatech.edu" |
sudo openconnect \
--protocol=gp \
vpn.gatech.edu \
--user=shuan7 \
--passwd-on-stdin
end
function vpn-cleanup --on-signal SIGINT --description "post hook"
# if connected before disconnecting, reconnect to mullvad
if ! string match --entire --ignore-case -q -- disconnected $mullvad_status
mullvad connect
end
end
openresolv
- arch wiki - openresolv
- openresolv allows multiple programs to edit
/etc/resolv.conf
- install openresolv
pacman -S openresolv
- configuration file in
/etc/resolvconf.conf
- it seems openresolv works by itself by just specifying a nameserver:
# Configuration for resolvconf(8)
# See resolvconf.conf(5) for details
resolv_conf=/etc/resolv.conf
# If you run a local name server, you should uncomment the below line and
# configure your subscribers configuration files below.
#name_servers=127.0.0.1
name_servers=1.1.1.1
sudo resolvconf -u
to generate/etc/resolv.conf
unbound
- arch wiki - unbound
- dnsprivacy - DNS privacy clients
- mullvad - DNS over HTTPS and DNS over TLS
- mullavd - SOCKS5 proxy
- install unbound
pacman -S unbound
- install expat for DNSSEC verification
pacman -S expat
- using openresolv,
edit
/etc/resolvconf.conf
name_servers="::1 127.0.0.1"
resolv_conf_options="trust-ad"
private_interfaces="*"
unbound_conf=/etc/unbound/resolvconf.conf
- edit unbound config
/etc/unbound/unbound.conf
# include: "/etc/unbound/resolvconf.conf"
server:
prefetch: yes
hide-identity: yes
hide-version: yes
tls-system-cert: yes
forward-zone:
name: "."
forward-addr: 194.242.2.2@853#doh.mullvad.net
forward-addr: 193.19.108.2@853#doh.mullvad.net
# forward-addr: 1.1.1.1@853#cloudflare-dns.com
# forward-addr: 1.0.0.1@853#cloudflare-dns.com
forward-tls-upstream: yes
- if using vpn, resolvconf generated include should probably not be used, literally the definition of a DNS leak
- also seems to be broken, can't resolve servers because of mullvad firewall
- if using mullvad, should use local gateway, can't use TLS because domain name isn't known (10.64.0.1 corresponds to currently connected mullvad server, different hostname depending on which server you're currently connected to). This is annoying because then then the fallbacks can't use TLS. Could hypothetically fix by specifying a particular host. This is doubly annoying because the mullvad doh.mullvad.net DNS servers only use TLS, so they can't be used as fallbacks.
forward-zone:
name: "."
# https://mullvad.net/en/help/socks5-proxy/
forward-addr: 10.64.0.1
forward-addr: 1.1.1.1
forward-addr: 1.0.0.1
detailed notes
To enable DNSSEC for unbound, follow the instructions here.
Basically, to generate the root.key
file at /usr/local/etc/unbound
just run
sudo unbound-anchor
and to generate the root.hints
file (which is not strictly
necessary, as unbound comes with a default file, but if your package
manager doesn't update as often, you can update it yourself) run
curl --output /usr/local/etc/unbound/root.hints https://www.internic.net/domain/named.cache
conda
- install miniconda
paru -S miniconda3
- lightweight installer for conda that doesn't install as much as anaconda (over 250 packages by default)
- or micromamba, extremely minimal and fast re-implementation of conda
- what they want you to do (and what the post-install message will say)
source /opt/miniconda3/etc/fish/conf.d/conda.fish
- or if on bash/POSIX shell
source /opt/miniconda3/etc/profile.d/conda.sh
- will add
conda
toPATH
, to make changes permanent
conda init fish
- or
conda init
- but I don't necessarily want to have every shell startup be in (base)
- instead, comment out the addition to the configuration file and run the command manually when using conda
eval /opt/miniconda3/bin/conda "shell.fish" "hook" $argv | source
terminals database is inaccessible
export TERMINFO=/usr/share/terminfo
micromamba
- re-implementation of conda in C++
- uses
libsolv
, library used by Red Hat'sdnf
and others (see internals) - pretty much drop-in replacement, just much faster
nix
n.b.: this is a guide for using nix/entering nixos on archlinux
- arch wiki - nix
- install nix
pacman -S nix
- start daemon (allows operations on nix store without
sudo
/root)
sudo systemctl enable nix-daemon.service
sudo systemctl start nix-daemon.service
- add self to
nix-users
sudo gpasswd -a username nix-users
- don't use channels because not reproducible, so don't do the below
nix-channel --add https://nixos.org/channels/nixpkgs-unstable
nix-channel --update
- enable flakes and new CLI interface by editing
~/.config/nix/nix.conf
experimental-features = nix-command flakes
nix-collect-garbage
home-manager
- generate initial home-manager configuration
nix run home-manager/master -- init --switch
- problem with gc:
home-manager switch
nix-store --gc
home-manager switch
-
keeps clearing/re-downloading on every switch
-
looking at the stores: nixpkgs and home-manager, precisely the inputs to the flake
-
solution: use nix-direnv to register flake inputs as gc root
-
problem: failed to set locale
-
solution: set
LOCALE_ARCHIVE
to
/nix/store/{hash}-glibc-locales-{version}/lib/locale/locale-archive
installing nixos with kexec
- nixos manual - booting into nixos via kexec
- generate default/automatic configuration
(
configuration.nix
/hardware-configuration.nix
)
nixos-generate-config
- (optional) use flake template for
configuration.nix
nix flake new /etc/nixos -t github:nix-community/home-manager#nixos
configuration tips
- need to import
netboot-minimal.nix
imports =
[ # Include the results of the hardware scan.
./hardware-configuration.nix
(modulesPath + "/installer/netboot/netboot-minimal.nix")
];
- netboot-minimal.nix
disables loading
linux-firmware
, preventing gpu from working
# overwrite /installer/netboot/netboot-minimal.nix
hardware.enableRedistributableFirmware = lib.mkForce true;
- on luks, probably need to manually specify root partition
boot.initrd.luks.devices.cryptlvm.device =
"/dev/disk/by-uuid/5d57809c-d0e9-49e9-939e-f5d68392faf4";
# manually specify because `nixos-generate-config` doesn't pick it up
fileSystems."/" = {
device = "/dev/VolumeGroup/root";
fsType = "ext4";
};
- enable kernel flag
boot.shell_on_fail
to debug in case things go wrong
boot.kernelParams = [ "boot.shell_on_fail" ];
entering the build
- not risking normal build (overwrites bootloader), try
kexec
to prototype - arch wiki - kexec
pacman -S kexec-tools
- generate kernel image
nix-build '<nixpkgs/nixos>' \
-I /nix/store/{hash}-nixpkgs \
--arg configuration ./configuration.nix \
--attr config.system.build.kexecTree
-
if using flakes, path to nixpkgs can also be
-I nixpkgs=flake:nixpkgs
-
turn off kernel mode setting
-
/etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="... quiet loglevel=3 ... nomodeset"
-
remove
amdgpu
kernel module -
/etc/mkinitcpio.conf
MODULES=()
- reload grub/initramfs, reboot, go into vt, run
sudo ./result/kexec-boot
pacman
pacman -S pacman-contrib
basic operations
- update
pacman -Syu
- if using aur helper
paru
- install package (package search or search in aur)
pacman -S pkgname
- if in AUR
paru -S pkgname
- remove package and its dependencies and configuration files
pacman -Rns pkgname
searching
- package list
pacman -Q
- search for package
pacman -Qs query
- package information
pacman -Qi pkgname
- list of files installed by package
pacman -Ql pkgname
- list aur packages
pacman -Qm
- list explicitly installed packages
pacman -Qe
- list all explicitly installed native packages (not aur) that are not direct or optional dependencies
pacman -Qent
orphans
- list and remove all orphan packages
pacman -Qtdq | pacman -Rns -
- include optional requirements as well
pacman -Qttdq
- even more aggressive (account for cycles etc.)
pacman -Qqd | pacman -Rsu --print -
cache
- clear cache (
/var/cache/pacman/pkg/
) except for last three versions (frompacman-contrib
)
paccache -r
- clear cache except for currently installed packages
pacman -Sc
- clear cache completely
pacman -Scc
rollbacks
- check
/var/cache/pacman/pkg/
for old version - use
pacman -U pkgname.pkg.tar.zst
if it exists - otherwise check Arch Linux Archive available at https://archive.archlinux.org/packages/
pacman -U https://archive.archlinux.org/packages/path/packagename.pkg.tar.zst
- if downgrade, pin version so pacman doesn't update it
- edit
/etc/pacman.conf
and add package toIgnorePkg
# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup
IgnorePkg = pkgname
reflector
- arch wiki - reflector
- install reflector
pacman -S reflector
- automatically update mirrorlist to select fastest mirrors
- edit
/etc/xdg/reflector/reflector.conf
--save /etc/pacman.d/mirrorlist # set the output path
--protocol https # force https
--country us # set country (get list with `reflector --list-countries`)
--latest 50 # use only the 50 most recently synchronized mirrors (--latest)
--sort rate # sort the mirrors by download speed
sudo systemctl start reflector.service
- or
reflector --protocol https --country us --latest 50 --sort rate --save /etc/pacman.d/mirrorlist
- I like
https://iad.mirrors.misaka.one/archlinux/$repo/os/$arch
:)
AUR helper
- yay
- paru
- written in rust so it must be better
- also forces you to check
PKGBUILD
s (which we do read carefully right?) - if migrating from other AUR helper
paru --gendb
pacgraph
- pacgraph makes a graph visualization of all installed packages
paru -S pacgraph
- generate graph (svg)
pacgraph -f packages
- convert to png with imagemagick
convert packages.svg packages.png
- or ffmpeg
ffmpeg -i packages.svg packages.png
- mine below
browserpass
- browserpass
- install native app
pacman -S browserpass
- install firefox extension
pacman -S browserpass-firefox
- install chrome extension
paru -S browserpass-chrome
- remember to quit and re-open chrome!
browserpass
pass can be used to autofill username and password forms in the browser through the browserpass extension. It is installed in two parts, first, a native messaging host, and second, an extension for the browser.
The native app can be installed with
pacman -S browserpass
Install the Firefox extension with
pacman -S browserpass-firefox
Or the Chrome extension (AUR) with
paru -S browserpass-chrome
Remember to quit and re-open the browser after installing the extension.
In order to use browserpass, the directory structure
and file structure needs to be organized in a
particular way.
This was a bit of pain to migrate from whatever ad-hoc format I was using
previously, but it didn't take too long. I recommend putting the password
on the first line with no prefix so things like pass -c file
still work,
and specifying the username with username: ...
.
gnupg
- arch wiki - GnuPG
- install
pacman -S gnupg
- set
pinentry
program (should use something graphical for background)
pacman -Ql pinentry | grep /usr/bin/
- also add
ssh
support - edit
~/.gnupg/gpg-agent.conf
# set SSH_AUTH_SOCK to use gpg-agent instead of ssh-agent
enable-ssh-support
# use alternative pinentry
pinentry-program /usr/bin/pinentry-qt
- copy over old data (private keys, revocation certificates)
mullvad
- can't import keys from keyserver with mullvad!
yubikey
- see yubikey
pass
- arch wiki - pass
- install pass
pacman -S pass
passmenu
securing
- set
PASSWORD_STORE_SIGNING_KEY
set -gx PASSWORD_STORE_SIGNING_KEY "EA6E27948C7DBF5D0DF085A10FBC2E3BA99DD60E"
- this requires a signature on
.gpg-id
and non-system extensions - if, for example, using remote git to track and pull update to
.gpg-id
or malicious extension, won't be used because signature breaks - generate signature
gpg --detach-sign .gpg-id
- do the same for any non-system extensions (not recommended)
- enable non-system extensions (if extension isn't packaged, e.g.)
set -gx PASSWORD_STORE_ENABLE_EXTENSIONS "true"
pass-otp
- see pass-otp
browserpass
- see browserpass
git-credential-manager
detailed notes
pass is a simple GPG-based command-line password manger. To install, run
pacman -S pass
Note that the archlinux package comes with dmenu integration, with the binary
passmenu
Setting a signing key
In order to set a signing key, use the
environmental variable PASSWORD_STORE_SIGNING_KEY
set -gx PASSWORD_STORE_SIGNING_KEY "EA6E27948C7DBF5D0DF085A10FBC2E3BA99DD60E"
Setting this is in order to require a signature on .gpg-id
and non-system
extensions. For example, if you are using a remote git server to track your
password store; if you pull an update to .gpg-id
that contains a different
key from the one you usually use, you won't encrypt new passwords to the
malicious key because the signature will break. New local extensions or
modifications to existing extensions won't happen for the same reason.
In order to generate a signature, run
gpg --detach-sign .gpg-id
Do the same for any non-system extensions. However, it's probably more secure to install extensions with your system's package manager, since these packages will be automatically updated and also signed by the package maintainer. If an extension isn't packaged, you can enable non-system extensions with
set -gx PASSWORD_STORE_ENABLE_EXTENSIONS "true"
pass-otp
- install pass-otp
pacman -S pass-otp
- automatically updates and checks gpg signature
- probably more secure than copying to
.extensions
folder and signing
TOTP 2fa (pass-otp)
With the pass-otp extension, pass can generate time-based one-time passwords (TOTP). These are commonly used in two-factor authentication (the 6 digit codes that change every set period of time, usually every 30 seconds). Usually these are loaded into an app like Google Authenticator by scanning a QR code. However, one can usually show the secret directly, which can be stored in pass. Note that storing two-factor secrets in pass along with your passwords kind of defeats the point of two-factor authentication; stronger two-factor authentication can be achieved with hardware tokens like yubikeys.
pass-otp can be installed with
pacman -S pass-otp
A TOTP URI is then added to the password file in the following format:
otpauth://totp/SERVICE:USERNAME?secret=AAAAAAAAAAAAAAAA&issuer=SERVICE
texlive
- arch wiki - TeX Live
- really the only required package
pacman -S texlive-core
- install a lot of TeX live packages
pacman -S texlive-most
pacman -S texlive-lang
- install biber (biblatex backend)
pacman -S biber
- tlmgr (tex live package manager) is broken, can install alternative
paru -S tllocalmgr-git
- but let's be real, how often do you install something with
tlmgr
?
tectonic (LaTeX compiler)
PACE
- project directory
~/p-fschaefer7-0
- home directory
/storage/home/hcoda1/6/shuan7
- scratch (temp)
~/scratch
logging in
- need to run GT VPN (GlobalProtect)
- logging in:
- (kitty sets
$TERM
wrong)
TERM=xterm-color ssh shuan7@login-phoenix.pace.gatech.edu
- (GT password)
- to see headnodes
pace-whoami
transferring files
- transferring files
- just use
scp
/rsync
...
submitting jobs
- submitting jobs
- account
gts-fschaefer7
- see accounts
pace-quota
- see queue status
pace-check-queue -c inferno
- make slurm file
#!/bin/bash
#SBATCH -Jcknn-cg # job name
#SBATCH --account=gts-fschaefer7 # charge account
#SBATCH --nodes=1 # number of nodes and cores per node required
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=8
#SBATCH --mem-per-cpu=22gb # memory per core
#SBATCH -t48:00:00 # duration of the job (hh:mm:ss)
#SBATCH -qinferno # QOS name
#SBATCH -ojobs/cg_%j.out # combined output and error messages file
cd $SLURM_SUBMIT_DIR # change to working directory
# load modules
module load anaconda3
# enter conda virtual environment
conda activate ./venv
# run commands
lscpu
lsmem
time srun python -m experiments.cg
- submit job to scheduler (two queues:
inferno
andembers
)
sbatch job.sbatch
-
job inherits current directory, have to run
sbatch
from proper directory! -
submitted job status
squeue -u shuan7
interactive session
- request interactive session
salloc -A gts-fschaefer7 -q inferno -N 1 --ntasks-per-node=4 -t 1:00:00
- for gpu
salloc -A gts-fschaefer7 -q inferno -N 1 --gres=gpu:A100:1 --mem-per-gpu=12G -t 0:15:00
software
modules
conda
A (f)ast re-write of p(ar) - far
This is an old plaintext copy of the post on my blog.
par
is a formatting tool that inserts line
breaks to make the length of each line less than a set number of characters,
usually 79 (terminals historically have 80 width). Unfortunately, par
is
incredibly complicated and introduces random whitespace. So I made my own.
For far
to make the paragraphs look good, it minimizes the variance of
each line. However, it's constrained to use the fewest number of lines
possible, so it doesn't generate really short lines. Finally, it ignores
the last line when minimizing variance and tries to make the last line
shorter than average, because a typical paragraph usually looks better
if the last line is shorter. To summarize,
- Minimize the variance of the lengths of each line ...
- ... subject to the constraint that the number of lines is smallest
- Ignore the last line, while making sure it's shorter than average
far
uses dynamic programming to minimize variance. It
tokenizes the paragraph by splitting on whitespace, and each
subproblem in the dynamic program is a suffix of this token list.
Var[X] = E[X]^2 - E[X]^2 = sum(x^2 for x in X)/len(X) - (sum(X)/len(X))^2
The length len(X)
is constant because of the smallest number of lines
constraint, and so is the sum because the sum of the line lengths is
determined by two things: the characters in the tokens and the number of
spaces introduced by merging two tokens (combining the words "hello" and
"world" onto the same line gives "hello world", with an additional space).
The characters stay the same, and the number of spaces is fixed if the
number of lines is fixed. Each token starts off as its own line, and each
merge reduces the number of lines by 1, so if two solutions have the same
number of lines, they must have done the same number of merges.
Thus, minimizing Var[X]
is equivalent to minimizing the sum of squares
sum(x^2 for x in X)
if the number of lines is fixed. Recall that we
are trying to minimize variance over the entire paragraph. The overall
paragraph has some mean value u. Each line will contribute (x - u)^2
to the overall paragraph's variance. So we want to minimize:
(x1 - u)^2 + (x2 - u)^2 + ... + (xn - u)^2
where xi is the length of a line and we know that x1 + x2 + ... + xn
is
constant because of the above logic (sum(X)
is constant). Expanding,
[x1^2 - 2u x1 + u^2] + [x2^2 - 2u x2 + u^2] + ... + [xn^2 - 2u xn + u^2]
u^2 is a constant, so we can discard those terms and reorganize into
[x1^2 + x2^2 + ... + xn^2] - 2u[x1 + x2 + ... + xn].
The last term is a constant, so minimizing the variance of the overall paragraph is equivalent to minimizing the variance for a suffix of the paragraph (both are minimizing the sum of squares). This is just the variance of the subproblem, so the dynamic programming is valid since optimal substructure holds. In practice, I skip calculating variance entirely and simply minimize the sum of squares. I also do dynamic programming on the variance of each prefix, so that I can easily ignore the last line.
That's it! The algorithm runs in O(NK)
where N is the number of characters
in the input text and K is the desired width. Since K is usually fixed to
some small constant (79, 72, etc.), this is essentially linear in N and I
suspect most of the running time is bottlenecked by just I/O (reading the
input text and printing out the formatted text). Running with a width of
79 on a 1MB file with over 20,000 lines takes under 200 milliseconds. For
100MB, fmt
takes around 11.9 seconds, par
takes 15.7, and far
takes
16.6. So far
is slightly slower than the others, but certainly not enough
to be noticeable for "reasonable" inputs, especially if output is redirected
into a file rather than displayed to terminal.
Examples
original paragraph:
xxxxx xxx xxx xxxx xxxxxxxxx xx x xxxxxxxxx x xxxx xxxx xxxxxxx xxxxxxxx xxx
xxxxxxxxx xxxxxxxx xx xx xxxxx xxxxx xxxx xx x xxxx xx xxxxxxxx xxxxxxxx xxxx
xxx xxxx xxxx xxx xxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxx xxx xxxxx xx xxxx x xxxx
xxxxxxxx xxxx xxxx xx xxxxx xxxx xxxxx xxxx xxxxxxxxx xxx xxxxxxxxxxx xxxxxx
xxx xxxxxxxxx xxxx xxxx xx x xx xxxx xxx xxxx xx xxx xxx xxxxxxxxxxx xxxx xxxxx
x xxxxx xxxxxxx xxxxxxx xx xx xxxxxx xx xxxxx
fmt -w 72
(greedy algorithm):
xxxxx xxx xxx xxxx xxxxxxxxx xx x xxxxxxxxx x xxxx xxxx xxxxxxx xxxxxxxx
xxx xxxxxxxxx xxxxxxxx xx xx xxxxx xxxxx xxxx xx x xxxx xx xxxxxxxx
xxxxxxxx xxxx xxx xxxx xxxx xxx xxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxx xxx
xxxxx xx xxxx x xxxx xxxxxxxx xxxx xxxx xx xxxxx xxxx xxxxx xxxx
xxxxxxxxx xxx xxxxxxxxxxx xxxxxx xxx xxxxxxxxx xxxx xxxx xx x xx xxxx
xxx xxxx xx xxx xxx xxxxxxxxxxx xxxx xxxxx x xxxxx xxxxxxx xxxxxxx xx xx
xxxxxx xx xxxxx
par 72
(with PARINIT
set to rTbgqR B=.,?'_A_a_@ Q=_s>|
):
xxxxx xxx xxx xxxx xxxxxxxxx xx x xxxxxxxxx x xxxx xxxx xxxxxxx xxxxxxxx
xxx xxxxxxxxx xxxxxxxx xx xx xxxxx xxxxx xxxx xx x xxxx xx xxxxxxxx
xxxxxxxx xxxx xxx xxxx xxxx xxx xxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxx
xxx xxxxx xx xxxx x xxxx xxxxxxxx xxxx xxxx xx xxxxx xxxx xxxxx xxxx
xxxxxxxxx xxx xxxxxxxxxxx xxxxxx xxx xxxxxxxxx xxxx xxxx xx x xx xxxx
xxx xxxx xx xxx xxx xxxxxxxxxxx xxxx xxxxx x xxxxx xxxxxxx xxxxxxx xx xx
xxxxxx xx xxxxx
far 72
:
xxxxx xxx xxx xxxx xxxxxxxxx xx x xxxxxxxxx x xxxx xxxx xxxxxxx
xxxxxxxx xxx xxxxxxxxx xxxxxxxx xx xx xxxxx xxxxx xxxx xx x xxxx
xx xxxxxxxx xxxxxxxx xxxx xxx xxxx xxxx xxx xxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxx xxx xxxxx xx xxxx x xxxx xxxxxxxx xxxx xxxx xx xxxxx
xxxx xxxxx xxxx xxxxxxxxx xxx xxxxxxxxxxx xxxxxx xxx xxxxxxxxx
xxxx xxxx xx x xx xxxx xxx xxxx xx xxx xxx xxxxxxxxxxx xxxx xxxxx
x xxxxx xxxxxxx xxxxxxx xx xx xxxxxx xx xxxxx
Looking at the output of the greedy algorithm, because it always forms a line if it's possible, it creates highly variable line lengths. For example, there are many "valleys" where a line is shorter than the lines adjacent to it, like lines 2 and lines 4, giving the overall paragraph a jagged appearance.
par
improves on fmt
, but still creates a single large valley. Finally,
I would argue that far
creates the most aesthetically pleasing paragraph
because it minimizes the variance, creating the smoothest paragraph edge.
It's probably possible to modify PARINIT
for par
to work properly on this
example, and in general par
works quite well, but it's hard to work through
the documentation to find precisely what to do and the recommended PARINIT
in the man page should work well. far
works well "out of the box" and for
better or for worse, only has a single configuration parameter --- width.
Uses
This program is pretty useful whenever writing plaintext in a monospace text
editor, e.g. when editing LaTeX, markdown files, college essays, and emails.
It's especially useful in vim
, which lets you set the option 'formatprg'
so the operator gq
formats using the external program.
archlinux on a tuxedo pulse
- CPU: AMD Ryzen 7 4800H with Radeon graphics
- wikipedia - radeon
- Renoir (2020) table, Ryzen 7 4800H -> GCN 5th gen architecture
- GPU: Radeon RX Vega 7 (AMD ATI 04:00.0 Renoir)
- Driver AMDGPU
- fn + space to change keyboard backlight
- LVM on LUKS (LVM in encrypted drive)
- what tuxedo does by default
- filesystem: ext4
- bootloader: grub
uefi
- enter by holding
F2
on boot - or by selecting corresponding entry in GRUB
- settings:
- put USB first in boot order
- put GRUB second in boot order
- turn off secure boot (enable later)
- disable webcam
live boot
- need to set proper UEFI order (enter UEFI with USB plugged in)
- to get started
cryptsetup open /dev/nvme0n1p3 cryptlvm
mount /dev/VolumeGroup/root /mnt
arch-chroot /mnt
boot process
- Power on --- Tuxedo logo (avoidable?)
- bootloarder: grub
- splash screen: plymouth
- display manager: sddm
- window manager: i3
miscellaneous
usb
- arch wiki - USB storage devices
- find name of device with
lsblk -f
- mount (folder needs to exist, make with
mkdir
)
sudo mount /dev/sda2 /mnt
- unmount
sudo umount /mnt
pdf viewers
mkinitcpio
sudo mkinitcpio -P
==> WARNING: Possibly missing firmware for module: xhci_pci
-> Running build hook: [keymap]
-> Running build hook: [consolefont]
-> Running build hook: [modconf]
-> Running build hook: [block]
==> WARNING: Possibly missing firmware for module: wd719x
==> WARNING: Possibly missing firmware for module: qla2xxx
==> WARNING: Possibly missing firmware for module: qed
==> WARNING: Possibly missing firmware for module: qla1280
==> WARNING: Possibly missing firmware for module: aic94xx
==> WARNING: Possibly missing firmware for module: bfa
-> Running build hook: [plymouth-encrypt]
==> WARNING: Possibly missing firmware for module: qat_4xxx
- can install mkinitcpio-firmware
paru -S mkinitcpio-firmware
- however, warnings are harmless if nothing is broken
- one of those cases where the "solution" may be more dangerous than the problem
virtual terminal
- arch wiki - linux console
- switch with
ctrl+alt+F[1-6]
- graphical session (if running) is typically terminal 1, at least for sddm
set consolefont
- arch wiki - linux console
sudo mkinitcpio -P
==> WARNING: consolefont: no font found in configuration
- list of fonts
/usr/share/kbd/consolefonts/
, installed by the kbd package - switch to virtual terminal for the following
- display font table
showconsolefont
- set font
setfont
- edit configuration file
/etc/vconsole.conf
, seeman vconsole.conf
FONT=Lat2-Terminus16
- default font cp437, appears not to be in folder and instead built-in to kernel
- webpage of fonts
.psfu
indicates Unicode translation map built-in- package for popular terminus font, includes more sizes than kbd
pacman -S terminus-font
proper naming
-
Arch Linux
Arch should be referred to as:
- Arch Linux
- Arch (Linux implied)
- archlinux (UNIX name)
Archlinux, ArchLinux, archLinux, aRcHlInUx, etc. are all weird, and weirder mutations.
Officially, the 'Arch' in "Arch Linux" is pronounced /ˈɑrtʃ/ as in an "archer"/bowman, or "arch-nemesis", and not as in "ark" or "archangel".
-
can never remember what the "official" names are
install
making live USB
- arch wiki - installation guide
- Download ISO [torrent link]
- Download PGP signature and check checksums on ISO download page
- Verify PGP signature
gpg --keyserver-options auto-key-retrieve --verify archlinux-version-x86_64.iso.sig
- arch wiki - USB flash installation medium
- copy ISO to USB
cp path/to/archlinux-version-x86_64.iso /dev/sdx
- boot from USB (make sure to set correct UEFI order)
in live environment
- Connect to WiFi (iwd)
iwctl
[iwd]# help
[iwd]# station list
[iwd]# station wlan0 connect WIFI_NAME
[iwd]# station list
- Check connection
ping archlinux.org
- Set system clock
timedatectl set-ntp true
- Check system time
timedatectl status
partition disk
- Partition disks: only need UEFI (EFI system partition) and root (/)
- Swap does not need to be a partition, can be a file for flexibility/ease
lsblk
fdisk -l
If Tuxedo: by default, partitions look like (1 TB drive)
Devic ... Size Type
/dev/nvme0n1p1 1G EFI System
/dev/nvme0n1p2 512M Microsoft basic data
/dev/nvme0n1p3 930G Linux filesystem
- Normally could use existing EFI partition
- But file format is wrong (we want FAT32 for GRUB, format is ext3)
- Will fix later
prepare drive for encryption
- arch wiki - solid state drive memory cell cleaning
- Can clean SSD before this step if desired
- arch wiki - prepare drive for dm-crypt
- Create temporary encrypted container
cryptsetup open --type plain -d /dev/urandom /dev/nvme0n1p3 to_be_wiped
- Verify that it exists
lsblk
- Wipe container with zeros
dd if=/dev/zero of=/dev/mapper/to_be_wiped status=progress
WARNING: 1 TB disk capacity / (80 MB/s write speed) = ~3.5 hours
- Close temporary container
cryptsetup close to_be_wiped
encrypt entire drive
- arch wiki - dm-crypt encrypting an entire system
- Use LVM on LUKS (logical volume manager inside encrypted disk)
- Create LUKS encrypted partition on system partition
cryptsetup luksFormat /dev/nvme0n1p3
- Open container (decrypted container now at
/dev/mapper/cryptlvm
)
cryptsetup open /dev/nvme0n1p3 cryptlvm
- Create physical volume
pvcreate /dev/mapper/cryptlvm
- Create volume group (name
VolumeGroup
, arbitrary)
vgcreate VolumeGroup /dev/mapper/cryptlvm
- Create logical volumes
- I said we could use a swap file
- If using LVM, easy to re-size partitions, might as well use swap partition
- Make swap partition same size as RAM for easy suspend to disk (hibernate)
- Don't use entire volume group capacity for easy resizing in the future
lvcreate -L 32G VolumeGroup -n swap
lvcreate -l 100%FREE VolumeGroup -n root
- Format filesystems
mkswap /dev/VolumeGroup/swap
mkfs.ext4 /dev/VolumeGroup/root
- Mount filesystems
swapon /dev/VolumeGroup/swap
mount /dev/VolumeGroup/root /mnt
-
(n.b. the above steps also work for external storage, e.g. a backup drive)
-
Prepare boot partition
mkfs.fat -F 32 /dev/nvme0n1p1
mkdir /mnt/boot
mount /dev/nvme0n1p1 /mnt/boot
- Select mirrors with
reflector
- arch wiki - reflector
pacstrap
to install base, kernel, firmware
pacstrap /mnt base linux linux-firmware
- Generate fstab
genfstab -U /mnt >> /mnt/etc/fstab
switch into new system
- Change root into new system
arch-chroot /mnt
- Install necessary packages
pacman -S lvm2 grub efibootmgr iwd
- Install useful packages
pacman -S man-db man-pages neovim fish
- Set timezone
ln -sf /usr/share/zoneinfo/US/Eastern /etc/localtime
- Run
hwclock
hwclock --systohc
- Edit
/etc/locale.gen
and uncommenten_US.UTF-8 UTF-8
, runlocale-gen
locale-gen
- Create
/etc/locale.conf
with theLANG
variable
LANG=en_US.UTF-8
- Create hostname in
/etc/hostname
myhostname
- Set root password
passwd
edit initramfs
- Add the following to
/etc/mkinitcpio.conf
HOOKS=(base udev autodetect keyboard keymap consolefont modconf block encrypt lvm2 filesystems fsck)
- Recreate initramfs image
mkinitcpio -P
install GRUB
- arch wiki - GRUB
- EFI system partition already mounted to
/boot
- Install GRUB
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB
- Edit
/etc/default/grub
wheredevice-UUID
is the UUID of/dev/nvme0n1p1
- This can be found with
lsblk -f
GRUB_CMDLINE_LINUX_DEFAULT="cryptdevice=UUID=device-UUID:cryptlvm root=/dev/VolumeGroup/root resume=/dev/VolumeGroup/swap"
- Use
grub-mkconfig
to generate/boot/grub/grub.cfg
grub-mkconfig -o /boot/grub/grub.cfg
- Reboot
reboot
- Hopefully the following:
- "Arch Linux" appears in GRUB menu
- Prompt for encryption key
- Prompt for username
- Prompt for password
- Login successful!
post-install
- Start WiFi with
iwd
and DNS - arch wiki - users and groups
- Add new user account
- Make sure shell is in
/etc/shells
or unable to log in
useradd -m -s /usr/bin/fish username
- Set password
passwd username
- Give
sudo
permission
EDITOR=nvim visudo
- Go to "User privilege specification" and add
USER_NAME ALL=(ALL) ALL
- Logout of root and log in to user account
exit
- or switch user
su stephenhuan
- arch wiki - XDG user directories
- Install xdg-users-dirs
sudo pacman -S xdg-user-dirs
- Create user directories
xdg-user-dirs-update
- Install AUR helper paru
sudo pacman -S --needed git base-devel
git clone https://aur.archlinux.org/paru.git
cd paru
sudo makepkg -si
- Get dotfiles with yadm
cd ~
pacman -S yadm
yadm clone https://github.com/stephen-huan/dotfiles
- Install display manager
sudo pacman -S sddm
- Enable display manager
sudo systemctl enable sddm.service
- Install window manager (i3)
sudo pacman -S i3
- Install terminal emulator (alacritty)
sudo pacman -S alacritty
- Enter graphical
sudo systemctl start sddm.service
- If no terminal emulator, can get suck in i3!
- Use
ctrl+alt+F[1-6]
to switch to virtual console - From virtual console back to graphical
sudo systemctl restart sddm.service
audio
- arch wiki - sound system
- ALSA: kernel driver
- PipeWire/PulseAudio on top
- bluetooth: bluez
- mpris: playerctl
Music applications
Apple Music
- use web client: music.apple.com
- pros: no installation/configuration
- cons: many
- need apple device for 2fa sign in
- this is not true
- feels slow/clunky
- randomly breaks
- doesn't store place
- need apple device for 2fa sign in
iTunes
- this is possible to wine but is broken on the latest version
- black screen from some rendering issue
- version list: https://www.theiphonewiki.com/wiki/ITunes
- doesn't seem to be able to import many things, randomly crashes
- https://forums.linuxmint.com/viewtopic.php?t=292556
- probably not worth the effort, just use cider, an open-source electron Apple Music client
Sync music
sync to iphone
- to replace sync to iPhone feature see arch wiki - ios
- install ifuse to allow access to filesystem from linux (uses libimobiledevice)
pacman -S ifuse
- if freezes on write (see #63, probably fixed in newest versions) try aur
paru -S ifuse-git
- use vlc on phone since simple copying directly to folder, see provided fish script
function musicsync --description "sync music to phone"
# mount vlc media folder to ~/mnt
ifuse --documents org.videolan.vlc-ios ~/mnt
# see https://superuser.com/questions/1192448/rsync-mkstemp-filename-failed-function-not-implemented-38
rsync -av --progress --no-perms --no-owner --no-group --exclude "*.m3u" \
~/Music/personal ~/mnt/
# copy playlists from cmus
set temp (pwd)
cd ~/Music/personal/playlists
python cmus_copy.py
# generate playlists from artists
python artist_playlist.py
cd "$temp"
rsync -av --progress --no-perms --no-owner --no-group \
~/Music/personal/playlists ~/mnt/personal
# done
umount ~/mnt
end
sync to android
- see android-tools
- syncing music
function musicsync --description 'sync music to phone'
# copy playlists from cmus
set temp (pwd)
cd ~/Music/personal/playlists
python cmus_copy.py
# generate playlists from artists
python artist_playlist.py
cd "$temp"
# copy over to phone
adb push --sync ~/Music/ /storage/self/primary/
end
clipboard
For an overview of the X window system's approach to the clipboard, see Arch wiki - clipboard. The summary is that the clipboard is managed by X, and has three distinct selections.
PRIMARY
: selected text, i.e. highlighted by mouse,CLIPBOARD
: text that is explicitly copied (e.g. byctrl-c
),SECONDARY
: no agreed upon purpose.
In order to manage these selections, install some command-line tool like xclip.
pacman -S xclip
For example, to copy a screenshot (taken with the package maim) to the clipboard,
maim --select --nodrag | xclip -selection clipboard -target image/png
Packages might also use xsel, so it's probably best to have both installed.
pacman -S xsel
losing history
By default, the clipboard contents are lost if the application the is data from is closed. For example, if one opens a terminal window, types some text, then copies the text, it can be pasted somewhere else. But once the terminal window is closed, one can no longer paste the text --- it is lost.
This is because X only stores references to the data, not copies. See the Ubuntu wiki for more information as well as this Reddit post. The Ubuntu article recommends Parcellite while the Reddit post recommends clipmenu. The Arch wiki also has a list of clipboard managers.
Most clipboard managers don't directly solve the persistence issue. Instead, they maintain a history of everything that is copied, and if the selection is lost, one can use a command-line interface or open a GUI to select a previous entry and re-copy it to the clipboard.
But I don't want to have to manually re-copy the last thing I copied, I just want to be able to keep the entry in my clipboard if I close the application. I couldn't get clipmenu or clipcat to work like this.
xclipboard, the official X clipboard manager works, but it always launches a GUI window that can't be easily suppressed. Parcellite works but it's old and relies on GTK2. A modern replacement is ClipIt, but when I used it reminded me that there was a security concern: I sometimes copy passwords and other sensitive information to the clipboard, and all of these clipboard managers store data on disk as plaintext in a temporary directory. I wanted to find a clipboard manager that supported clipboard persistence without manual intervention while storing data only in memory, never touching disk.
For these reasons, I settled on clipster.
copy/paste
One can use the open-source tmk/qmk
firmware to bind physical keys to copy/paste. The relevant
keycodes are KC_CUT
, KC_COPY
, and
KC_PASTE
. The X keyboard event viewer xev
(pacman -S xorg-xev
)
shows that these are mapped to XF86Cut
(145) XF86Copy
(141), and
XF86Paste
(143), respectively. Support for these keys seems to be
built-in to X as well as most GUI applications.
gpu
- arch wiki - AMDGPU
- Install mesa for OpenGL/3D acceleration
sudo pacman -S mesa
- test mesa support
sudo pacman -S mesa-utils
glxinfo
- Install DDX driver for 2D acceleration
sudo pacman -S xf86-video-amdgpu
- Enable vulkan support
sudo pacman -S amdvlk
- test vulkan support
sudo pacman -S vulkan-tools
vulkaninfo
- Accelerated video decoding
pacman -S libva-mesa-driver mesa-vdpau
internet/networking
- arch wiki - network configuration
- wifi: iwd
- ethernet
- dhcp: dhcpcd or dhclient (deprecated)
- dns: openresolv + unbound
- vpn: mullvad, openconnect
ethernet
- arch wiki - network configuration/ethernet
- hypothetically simpler than wifi because directly plugged in
- check network interface name
ip link show
- something like this:
1: lo: ...
link/loopback ...
2: eno1: ...
link/ether ...
altname enp2s0
4: wlan0: ...
link/ether ...
- turn on:
ip link set eno1 up
- turn off:
ip link set eno1 down
systemd-networkd
- arch wiki - systemd-networkd
- probably just works
georgia tech
- need to remember to register new device at portal.lawn.gatech.edu!
- otherwise, garbage data when trying to make DNS query
- make sure ethernet is connected and DHCP is working
- check MAC address with
ip link
2: eno1: ...
link/ether MAC_ADDRESS brd ff:ff:ff:ff:ff:ff
altname enp2s0
DNS
- arch wiki - domain name resolution
- if just need quick functional DNS to install other things: systemd-resolved
- good DNS: openresolv + unbound
- DHCP seems to either do DNS or allow DNS to be done without an explicit DNS client...
- DNS is provided by (g)libc, see arch wiki - domain name resolution
systemd-resolved
systemctl start systemd-resolved
- probably just works
nsdo
- github - nsdo
- might be nice
input
Screen capture
- arch wiki - screen capture
- install maim
pacman -S maim
- take full-screenshot
maim file.png
- make selection with mouse (
--nodrag
for click twice instead of click-dragging)
maim --select --nodrag file.png
- install obs
pacman -S obs-studio
copying images to clipboard with maim/xclip
- see maim examples
security
- pgp: gnupg
- hardware security key: yubikey
- password manger: pass
- git authentication: git-credential-manager or pass-git-helper