Something went wrong. Try again.
my dotfiles as mostly literate conf from emacs (Org-mode) to nix-darwin
Something went wrong. Try again.
28%
Python 19%
Emacs Lisp 13%
Nix 11%
TypeScript 9%
Rust 5%
Lua 5%
C 4%
Shell 3%
Vim Script 2%
JavaScript <1%
Makefile <1%
M4 <1%
MATLAB <1%
Clojure <1%
Commits 1.7k
README.org
:PROPERTIES:
:CUSTOM_ID: vidbinas-dotfiles
:END:
#+TITLE: [[https://github.com/vidbina][vidbina]]'s dotfiles
#+STARTUP: overview
These dotfiles make my life slightly more convenient. Not promising they'll do the same for yours though. 😉
* Usage
My configuration is currently managed with [[https://github.com/nix-community/home-manager][home-manager]] for the better DX or UX. Before using home-manager, I manually managed symlinks from my config directory to this dotfiles repo. The use of [[https://www.gnu.org/software//stow/][GNU Stow]] was considered for a brief moment until I realized that Stow was written in Perl and I came to terms with my unwillingness to have a critical part of my stack based on tooling that brings me no joy 🙊 (on account of my troubled personal history with Perl).
#+begin_quote
[!WARNING]
This config is a bit of a mess and the dependency chain of tangled files kind of visualizes this. Reason being is that this repo has a bit of a wild history.
This started of as just a regular collection of dotfiles -- something that I could use through manual symlinking or a GNU Stow-like experience. When I got guided into the NixOS world by the good folks at c-base (Berlin), I started tacking my nix configs into [[https://github.com/vidbina/nixos-configuration][vidbina/nixos-configuration]]. At some point, I learned home-manager and started extending this dotfiles repo to manage user configurations through home-manager (hm). Somewhere in between, an Emacs phase happened with a reintroduction to literate configs. This informed a considerable refactoring of the dotfiles config in order to have more explanation or context for the at times cryptic declarative configuration code -- at least that was the idea. Eventually, I ended up switching from NixOS to MacOS, due to a coffee mishap, and shoehorned a nix-darwin config into the mix.
Point is: this repo has always been a pretty accurate reflection of my dotfiles at a given moment in time and since I've chaotically switched between tooling and systems quite a bit, the form of this config has shifted considerably in tandem as well. At times, for the better but in many cases for the worst as I made things more obscure. In a way, I overcomplicated this so much that I now need the literate config to even know what's going on. 😭 Skill issue on my side. I love Nix and the reliability it gives me. I love Emacs for the integrated config management tooling it gives me. I just need to organise this better sometime -- a hobby project.
#+end_quote
#+begin_src dot :file doc/sys-conf-setup.png :exports results
digraph G {
node_this [shape=box, label="README.org"]
// not defined in this file but referenced here
node_emacs_nix_darwin_nix [shape=box, label="emacs/nix-darwin.nix"]
node_emacs_hm_nix [shape=box, label="emacs/hm.nix"]
node_emacs_default_nix [shape=box, label="emacs/default.nix"]
node_rofi_default_nix [shape=box, label="rofi/default.nix"]
node_system_darwin_default_nix [shape=box, label="system/darwin/default.nix"]
node_flake_nix [shape=box, label="flake.nix"]
// defined in this file
node_common_nix [shape=box, label="common.nix"]
node_shell_nix [shape=box, label="shell.nix"]
node_x_nix [shape=box, label="x.nix"]
node_mail_nix [shape=box, label="mail.nix"]
node_machines_nix [shape=box, label="machines.nix"]
node_vim_nix [shape=box, label="vim.nix"]
node_multimedia_nix [shape=box, label="multimedia.nix"]
node_browser_nix [shape=box, label="browser.nix"]
node_doc_nix [shape=box, label="doc.nix"]
node_home_darwin_nix [shape=box, label="home-darwin.nix"]
node_home_linux_nix [shape=box, label="home-linux.nix"]
node_configuration_darwin_nix [shape=box, label="configuration-darwin.nix"]
node_nvim_init_vim [shape=box, label="nvim/init.vim"]
node_hammerspoon_init_lua [shape=box, label="hammerspoon/init.lua"]
node_this -> node_common_nix [label="tangles to"]
node_this -> node_shell_nix [label="tangles to"]
node_this -> node_x_nix [label="tangles to"]
node_this -> node_common_nix [label="tangles to"]
node_this -> node_shell_nix [label="tangles to"]
node_this -> node_x_nix [label="tangles to"]
node_this -> node_mail_nix [label="tangles to"]
node_this -> node_vim_nix [label="tangles to"]
node_this -> node_multimedia_nix [label="tangles to"]
node_this -> node_browser_nix [label="tangles to"]
node_this -> node_doc_nix [label="tangles to"]
node_this -> node_home_darwin_nix [label="tangles to"]
node_this -> node_home_linux_nix [label="tangles to"]
node_this -> node_nvim_init_vim [label="tangles to"]
node_this -> node_hammerspoon_init_lua [label="tangles to"]
node_this -> node_configuration_darwin_nix [label="tangles to"]
node_vim_nix -> node_common_nix [label="imported by"]
node_this -> node_machines_nix [label="tangles to"]
node_machines_nix -> node_flake_nix [label="imported by"]
node_vim_nix -> node_home_darwin_nix [label="imported by"]
node_emacs_hm_nix -> node_home_darwin_nix [label="imported by"]
node_common_nix -> node_home_linux_nix [label="imported by"]
node_doc_nix -> node_home_linux_nix [label="imported by"]
node_browser_nix -> node_home_linux_nix [label="imported by"]
node_x_nix -> node_home_linux_nix [label="imported by"]
node_multimedia_nix -> node_home_linux_nix [label="imported by"]
node_emacs_default_nix -> node_home_linux_nix [label="imported by"]
node_rofi_default_nix -> node_x_nix [label="imported by"]
node_emacs_nix_darwin_nix -> node_configuration_darwin_nix [label="imported by"]
node_system_darwin_default_nix -> node_configuration_darwin_nix [label="imported by"]
node_home_linux_nix -> node_shell_nix [label="imported by"]
node_home_darwin_nix -> node_shell_nix [label="imported by"]
node_configuration_darwin_nix -> node_flake_nix [label="loaded as module by"]
node_home_darwin_nix -> node_flake_nix [label="imported to hm.users.${user} by"]
// node_this -> node_default_nix [label="tangles to", style=dotted]
// node_this -> node_default_darwin_nix [label="tangles to", style=dotted]
// node_personal_example -> node_personal [style=dotted]
}
#+end_src
#+RESULTS:
[[file:doc/sys-conf-setup.png]]
#+begin_quote
[!NOTE]
Org-mode in Emacs is used such that I can read my config as a literate configuration and tangle the necessary config files directly from Emacs. The pro of this setup is that it provides me context, the big con, is that you need Emacs to compile the target files if you want to make changes. Making changes in the target files directly, will result to overwrites when anyone retangles the config. For files tangled from Emacs, I've tried to add a notice at the start of those files to make sure you have a reminder when visiting a tangled file to head back to the source to make changes.
#+end_quote
For convenience's sake, we have a Makefile with the makerules defined for key steps/actions:
#+begin_src makefile :noweb yes :tangle Makefile
SHELL = /usr/bin/env sh
HOME_MANAGER = home-manager
NIX_SHELL = nix-shell
DARWIN_REBUILD = sudo darwin-rebuild
HOSTNAME := $(shell hostname)
# Tangle all org files to generate configuration files
# Respects local variables in org files (e.g., trailing whitespace cleanup hooks)
.PHONY: tangle
tangle:
@echo "📝 Tangling org files..."
<<emacs-batch-tangle>>
@echo "✅ Tangling complete"
# Verify parity between tangled outputs and committed files.
# Fails if org sources were modified but tangled outputs weren't committed.
# Note: Only checks tangled outputs (.org files are excluded from diff)
.PHONY: verify-parity
verify-parity:
@echo "🔄 Checking parity..."
@if ! git diff --exit-code -- ':!*.org'; then \
echo "❌ Parity check failed - run 'make tangle' and commit"; \
exit 1; \
fi
@echo "✅ Parity check passed"
# Validate Nix configuration (fast, no actual build)
# Only checks that config evaluates correctly - catches syntax/reference errors
# Use this for quick feedback during development (~5-10 seconds)
.PHONY: validate
validate:
@echo "🔍 Validating Nix configuration..."
@nix flake check --no-build
@nix build .#darwinConfigurations.berlin-4corei7.system --dry-run
@echo "✅ Validation complete"
# Verify literate config integrity: tangle org sources, confirm parity
# with committed outputs, and validate the resulting Nix configuration.
# Run before pushing. Fast path (~10s with warm cache): no build step.
.PHONY: check-config
check-config: tangle verify-parity validate
@echo "✅ All checks passed"
# Build nix-darwin configuration (thorough but slower)
# Actually builds packages - catches compilation errors that validate misses
# Use before merging/deploying (takes minutes depending on cache)
.PHONY: nix-darwin-build
nix-darwin-build:
${DARWIN_REBUILD} check --flake .#${HOSTNAME}
# Deploy nix-darwin configuration (builds and activates)
# Actually switches your system to the new configuration
# Use after testing with nix-darwin-build
.PHONY: nix-darwin-switch
nix-darwin-switch:
${DARWIN_REBUILD} switch --flake .#${HOSTNAME}
# Default target - show help
.PHONY: help
help:
@echo "Available targets:"
@echo " make tangle - Tangle all org files to generate config files"
@echo " make verify-parity - Verify tangled outputs match committed files"
@echo " make validate - Validate Nix configuration without building"
@echo " make check-config - Verify literate config (tangle + parity + nix validate)"
@echo " make nix-darwin-build - Build nix-darwin config"
@echo " make nix-darwin-switch - Switch nix-darwin config"
.DEFAULT_GOAL := help
#+end_src
Observe the following snippet which can be used without opening Emacs yourself directly but still tangling any of the files:
#+begin_src bash :noweb-ref emacs-batch-tangle
emacs --batch \
--eval "(setq enable-local-variables :all)" \
--eval "(setq enable-local-eval t)" \
--eval "(setq org-confirm-babel-evaluate nil)" \
--eval "(require 'org)" \
--eval "(dolist (file '(\"README.org\" \"emacs/README.org\")) \
(find-file file) \
(message \"📌 Tangling file %s\" file) \
(hack-local-variables) \
(org-babel-tangle) \
(kill-buffer))"
#+end_src
** The easy way with home-manager
*** Configuring macOS with home-manager using nix-darwin
1. Ensure Nix is installed as outlined in https://github.com/NixOS/nix#installation
#+begin_src bash
curl -L https://nixos.org/nix/install | sh
#+end_src
2. Optionally install homebrew as outlined on https://brew.sh in case you want to manage some of your brew packages with Nix as well. Note that you may not need to manually add homebrew to your path if you use nix-darwin as the [[https://github.com/LnL7/nix-darwin/blob/0625792671837155708eed2af4cad43dc9c9d825/modules/homebrew.nix#L785-L793][homebrew activationScript]] will take care of it.
3. Optionally install Rosetta 2 for the case where it may be necessary since tools like Docker may rely on for some of their capability.
#+begin_src bash
softwareupdate --install-rosetta
#+end_src
4. Setup nix-darwin and apply the configuration as outlined in https://github.com/LnL7/nix-darwin/#step-2-installing-nix-darwin
#+begin_src bash
nix run nix-darwin -- switch --flake . --show-trace
#+end_src
On systems, where =darwin-rebuild= has already been installed, run the following command instead:
#+begin_src bash
darwin-rebuild switch --flake .
#+end_src
In case of =Error: invalid option: --no-lock= errors, try to update your flakes as suggested in [[https://github.com/LnL7/nix-darwin/issues/1369][nix-darwin issue 1369]].
In case of =error: experimental Nix feature 'nix-command' is disabled; use '--extra-experimental-features nix-command' to override= errors, try to run:
#+begin_src bash
nix --extra-experimental-features nix-command --extra-experimental-features flakes run nix-darwin -- switch --flake . --show-trace
#+end_src
5. Update the nix flakes using
#+begin_src bash
nix flake update
#+end_src
and if you just want to upgrade packages managed by brew, run:
#+begin_src bash
brew upgrade
#+end_src
6. In order to debug the config enter a Nix REPL and inspect the inputs and outputs by using tab-completion on the variables =inputs= and =outputs= after loading the Flake.
Enter the REPL with the following command:
#+begin_src bash
nix repl
#+end_src
Bring the input and output variables into the REPL scope by loading the Flake as follows:
#+begin_src text
:lf .
#+end_src
See relevant help information by running:
#+begin_src text
:?
#+end_src
See the [[*nix-darwin][nix-darwin configuration]] section for configuration/implementation details.
**** WIP Remove latent packages
On my old MacBook Pro, I started by installing and using home-manager first before deciding to use nix-darwin. This has created some nix-related configuration on my machine that nix-darwin did not fully overwrite when I applied that change. Because of this imperative change nonesense, I had latent QEMU and Emacs packages in my nix path (observeable through running =tree -L 2 ~/.nix-profile=).
I attempted to resolve this by removing the home-manager package from my profile:
#+begin_src bash
> nix profile list
0 - - /nix/store/8s1b5c5w06yxxqba1zkv8yvlcyjhr6y6-password-store-1.7.4
1 flake:nixpkgs#legacyPackages.x86_64-darwin.cachix github:NixOS/nixpkgs/1697b7d480449b01111e352021f46e5879e47643#legacyPackages.x86_64-darwin.cachix /nix/store/7hmy1x2ca3gdfkvm029qg5074xby10pi-cachix-1.6
2 flake:nixpkgs#legacyPackages.x86_64-darwin.cachix github:NixOS/nixpkgs/1697b7d480449b01111e352021f46e5879e47643#legacyPackages.x86_64-darwin.cachix /nix/store/7hmy1x2ca3gdfkvm029qg5074xby10pi-cachix-1.6
3 - - /nix/store/7z9x0izk35yzggjhlnvsmv3y4sahijmh-home-manager-path
#+end_src
and then rebuilding the config.
With this, I believe I messed up my config even more, so I had to uninstall nix-darwin altogether https://github.com/LnL7/nix-darwin#uninstalling and then remove all nix-related folders as outlined in https://nixos.org/manual/nix/stable/installation/uninstall#macos.
Pay attention to trigger the correct disk identifier (note that the numbers in the first column and the IDENTIFIER column may not be similar in terms of numbers.
#+begin_src bash
/dev/disk0 (internal, physical):
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *1.0 TB disk0
1: EFI EFI 314.6 MB disk0s1
2: Apple_APFS Container disk1 1.0 TB disk0s2
/dev/disk1 (synthesized):
#: TYPE NAME SIZE IDENTIFIER
0: APFS Container Scheme - +1.0 TB disk1
Physical Store disk0s2
1: APFS Volume Macintosh HD - Data 354.1 GB disk1s1
2: APFS Volume Preboot 1.9 GB disk1s2
3: APFS Volume Recovery 1.2 GB disk1s3
4: APFS Volume VM 20.5 KB disk1s4
5: APFS Volume Macintosh HD 9.2 GB disk1s5
6: APFS Snapshot com.apple.os.update-... 9.2 GB disk1s5s1
7: APFS Volume Nix Store 11.0 GB disk1s6
#+end_src
#+begin_src bash
sudo rm -rf /etc/nix /var/root/.nix-profile /var/root/.nix-defexpr /var/root/.nix-channels ~/.nix-profile ~/.nix-defexpr ~/.nix-channels
#+end_src
After this, I restart the installation process.
Reading [[https://gist.github.com/jmatsushita/5c50ef14b4b96cb24ae5268dab613050?permalink_comment_id=4054744#gistcomment-4054744][a comment on jmatsushita's config]] led me to believe that the removal of ~/.nix-profile may have broken my system further but then it seems that nix-darwin uses global profiles instead of user-based profiles, which suggests that the existence of ~/.nix-profile may have been a remnant of my pre-nix-darwin use of home-manager. For now it seems that enabling the emacs service in nix-darwin does not immediately expose a CLI-accessible command. I've resorted to enabling the service along with installing emacs as a systemPackage but I have to first confirm if the emacs service alone yields a system that exposes the emacs command in a standard shell.
**** Handling =ls: .: Operation not permitted= errors
On a completely fresh macOS machine you may encounter =ls: .: Operation not permitted= errors if Terminal has not been granted prior access to the full disk.
Navigate to the "Full Disk Access" setting and enable access for the Terminal.
[[file:doc/macOS.settings.EnableFullDiskAccess.png]]
**** Darwin
#+begin_src nix :noweb yes :tangle home-darwin.nix
# Tangled from README.org
{ config, pkgs, lib, inputs, dotfilesPath, ... }:
{
imports = [
<<home-darwin-imports>>
];
<<home-darwin>>
programs = {
<<home-darwin-programs>>
};
}
#+end_src
***** DONE Darwin Home-manager Config
:LOGBOOK:
- State "DONE" from "TODO" [2024-12-23 Mon 10:19] \\
DRY-ing up the Darwin home-manager config by using the Linux home-manager config isn't a reasonable since Linux and Darwin use different mechanisms to provide home-manager facilities and this isn't shareable between platforms. It's a home-manager vs nix-darwin thing.
:END:
- State "TODO" from [2023-10-04 Wed 14:20] \\
Refactor to reuse the shared hm and programs configurations that we've used for the Linux config earlier. We want to DRY the overal config up.
#+begin_src nix :noweb yes :noweb-ref home-darwin
home.stateVersion = "23.05";
home.packages = with pkgs; [
# dev-packages
<<dev-packages>>
# home-darwin-packages
<<home-darwin-packages>>
];
home.file = {
<<home-darwin-home-file>>
};
#+end_src
***** Sudo with TouchID
#+begin_src nix :noweb-ref nix-darwin
security.pam.services.sudo_local = {
enable = true;
reattach = true;
touchIdAuth = true;
};
#+end_src
***** Imports
****** COMMENT Import common
#+begin_src nix :noweb-ref home-darwin-imports
./common.nix
#+end_src
****** Import vim into Darwin config
#+begin_src nix :noweb-ref home-darwin-imports
./vim.nix
#+end_src
****** TODO COMMENT Import Darwin variant of Emacs
- State "TODO" from [2023-10-04 Wed 15:35] \\
Update default-darwin.nix and import this instead of the emacsnix-darwin.nix
#+begin_src nix :noweb-ref home-darwin-imports
./emacs/default-darwin.nix
#+end_src
*** Configuring Linux with home-manager
:PROPERTIES:
:CUSTOM_ID: home-manager
:END:
The use of home-manager is pretty straightforward especially with the convenient *nix shell* and the *Makefile* that make usage even easier. The general idea is as follows:
- [[file:shell.nix]] defines a shell environment that contains all packages needed to install or apply a configuration. The packages include *niv* which helps us manage versions of our packages, *home-manager* which actually manages our home environments (hence the name) and and some utils.
- [[file:Makefile]] contains some rules to simplify how we call home-manager inside of the nix-shell since it effectively reduces the UX down to =make= or =make test= calls as opposed to =home-manager -f ./home.nix -v -n build= and =home-manager -f ./home.nix switch= respectively (which you don't want to have to remember 🤷🏿♂️).
Typical use will be as follows:
1. Enter the nix-shell using =nix-shell --pure=
2. Configure your personal.nix to specify =home.username=, =home.homeDirectory= and =home.stateVersion= for your system
3. Optionally, update niv-managed packages by running =niv update= to update the sources files ([[file:nix/sources.json]] and [[file:nix/sources.nix]]), as demonstrated below:
#+begin_src bash
niv update home-manager
niv update nixpkgs
#+end_src
4. Run =make test= to test the home-manager configuration or =make= to install the configuration
5. Optionally, if package update step was completed (step 2 above), commit the changes made to the niv sources files
6. Profit 💰
#+begin_quote
[!TIP]
💡 Note that home-manager generated configuration files will be written somewhere to ~~/.config~, e.g.: ~~/.config/git/config~ for git.
#+end_quote
**** Core packages
We use niv to manage our dependencies and manage this throught the =pkgs-bleeding= which we set up in let blocks of shell.nix and common.nix:
#+begin_src nix :noweb-ref common-packages-let
nixpkgs-bleeding-src = sources."nixpkgs-bleeding";
pkgs-bleeding = import nixpkgs-bleeding-src { };
#+end_src
***** COMMENT Niv
#+begin_src nix :noweb-ref common-packages
pkgs-bleeding.niv
#+end_src
**** Shell
For home-manager to work, we define a nix-shell that we creates a controlled environment for our Makefile to work.
#+begin_src nix :noweb yes :tangle shell.nix
# Tangled from README.org
# From https://github.com/ryantm/home-manager-template
let
sources = import ./nix/sources.nix;
nixpkgs-src = sources."nixpkgs";
pkgs = import nixpkgs-src { };
hm-src = sources."home-manager";
nur-src = sources."NUR";
<<common-packages-let>>
in
pkgs.mkShell rec {
name = "home-manager-shell";
buildInputs = with pkgs; [
<<shell-build-inputs>>
];
<<shell-hook>>
}
#+end_src
The build inputs for our shell are:
#+begin_src nix :noweb yes :noweb-ref shell-build-inputs
<<common-packages>>
(import hm-src { inherit pkgs; }).home-manager
cacert # to resolve CA cert issue
hello
git
ncurses # to resolve tput issue
which
#+end_src
For the shell environment to be portable enough to run on both Linux and Darwin (macOS) systems, we define a /shell hook/ that will export a few environment variables into existence depending on the system.
#+begin_src bash :noweb-ref shell-hook-src
export NIX_PATH="nixpkgs=${nixpkgs-src}:home-manager=${hm-src}:NUR=${nur-src}"
export HOME_MANAGER_CONFIG=${system}
#+end_src
The above snippet is a bit of a cheat because we've formatted it as bash but some of the variable expansion work is being done by Nix and not Bash. 😅 We wrap the shell expressions into the following Nix statement to set =system= (see the cheat in the snippet above) and we basically pull in the sources through our niv sources file which is defined at the start of our [[file:shell.nix]] file.
#+begin_src nix :noweb yes :noweb-ref shell-hook
shellHook = with pkgs; let
system = (
if stdenv.isLinux
then "./home-linux.nix"
else
(if stdenv.isDarwin
then "./home-darwin.nix"
else "./home.nix")
);
in
''
<<shell-hook-src>>
'';
#+end_src
With all of this out of the way, running =make= should just drop us into a Nix shell with everything preconfigured and then run some incantation of =home-manager switch= in order to switch our home-manager-managed, pun intended, environment.
***** REPL
Enter a REPL by entering the nix-shell first (to set up the env var =NIX_PATH=) and then run the following statement to obtain a reference to the home-manager configuration:
#+begin_src nix
hm = import <home-manager/modules> { inherit pkgs; configuration = ./home-linux.nix; }
#+end_src
**** Linux
:PROPERTIES:
:header-args: :noweb-sep "\n\n"
:END:
#+begin_src nix :noweb yes :tangle home-linux.nix
# Tangled from README.org
{ lib, pkgs, ... }:
{
imports = [
./common.nix
./doc.nix
./browser.nix
./x.nix
./multimedia.nix
./emacs
];
fonts.fontconfig.enable = true;
home.packages = with pkgs; [
vokoscreen
montserrat
<<home-linux-packages>>
];
<<home-linux-services>>
}
#+end_src
****** X
#+begin_src nix :noweb yes :tangle x.nix
# Tangled from README.org
{ config, pkgs, lib, options, ... }:
{
imports = [
<<x-imports>>
];
home.packages = with pkgs; [
<<x-packages>>
];
xdg.mimeApps.defaultApplications = {
"text/html" = [ "xsel-copy-url.desktop" ];
"x-scheme-handler/about" = [ "xsel-copy-url.desktop" ];
"x-scheme-handler/ftp" = [ "xsel-copy-url.desktop" ];
"x-scheme-handler/http" = [ "xsel-copy-url.desktop" ];
"x-scheme-handler/https" = [ "xsel-copy-url.desktop" ];
"x-scheme-handler/unknown" = [ "xsel-copy-url.desktop" ];
};
nixpkgs.overlays = [
(self: super: {
<<linux-overlays>>
})
];
xdg.mimeApps = {
enable = true;
};
xsession = {
enable = true;
initExtra = ''
setxkbmap -option -model dell -layout us -variant intl -option lv3:caps_switch
'';
profileExtra = ''
hsetroot -solid '#ff9800'
'';
};
home.pointerCursor = {
name = "Vanilla-DMZ";
package = pkgs.vanilla-dmz;
size = 64;
x11 = {
enable = true;
defaultCursor = "tcross";
};
};
<<x-programs>>
services = {
<<x-services>>
};
}
#+end_src
#+begin_src nix :noweb-ref x-packages
brightnessctl
neofetch
peek
screenkey
xdotool
btop
#+end_src
******* colors
#+begin_src nix :noweb-ref x-packages
(writeScriptBin "colors" ''
# https://askubuntu.com/questions/27314/script-to-display-all-terminal-colors
for x in {0..8}; do
for i in {30..37}; do
for a in {40..47}; do
echo -ne "\e[$x;$i;$a""m\\\e[$x;$i;$a""m\e[0;37;40m "
done
echo
done
done
echo ""
'')
#+end_src
******* xsel-copy-url
We define an overlay in which we build an env that contains a script and the desktop item that our mimehandler can resolve to for the appropriate mimetypes.
#+begin_src nix :noweb-ref linux-overlays
xsel-copy-url = pkgs.buildEnv (
let
script = pkgs.writeScriptBin "xsel-copy-url" ''
url=$1
echo "$url" | ${pkgs.xsel}/bin/xsel -ib
${pkgs.libnotify}/bin/notify-send \
--category=url \
--urgency=low \
"🌍 Link Copied" "Paste to enter $url"
'';
in
{
name = "xsel-copy-url";
paths = [
script
(pkgs.makeDesktopItem {
name = "xsel-copy-url";
exec = "${script}/bin/xsel-copy-url %U";
comment = "Open link by copying it into the clipboard with xsel";
desktopName = "xsel-copy-url";
type = "Application";
categories = [
"Network"
"WebBrowser"
];
mimeTypes = [
"text/html"
"x-scheme-handler/http"
"x-scheme-handler/https"
"x-scheme-handler/ftp"
];
})
];
}
);
#+end_src
We add our previously added =xsel-copy-url= "package" to our configuration:
#+begin_src nix :noweb-ref x-packages
xsel-copy-url
#+end_src
******* URxvt
#+begin_src nix :noweb yes :noweb-ref x-programs
programs.urxvt = {
enable = true;
package = pkgs.rxvt-unicode;
<<urxvt-config>>
extraConfig = {
<<urxvt-extra>>
};
fonts = [
<<urxvt-fonts>>
];
keybindings = {
<<urxvt-keybindings>>
};
scroll = {
<<urxvt-scroll>>
};
};
#+end_src
******** Fonts
#+begin_src nix :noweb-ref urxvt-fonts
"xft:DejaVu Sans Mono:pixelsize=28:antialias=true"
"xft:Fira Code:size=28:antialias=true"
"xft:Iosevka:size=28:antialias=true"
#+end_src
******** ISO14755
#+begin_src nix :noweb-ref urxvt-config
iso14755 = false;
#+end_src
******** COMMENT Remove border
#+begin_src nix :noweb-ref urxvt-config
externalBorder = "0px";
#+end_src
******** Keybindings
#+begin_src nix :noweb-ref urxvt-keybindings
"C-minus" = "perl:font-size:decrease";
"C-plus" = "perl:font-size:increase";
"C-=" = "perl:font-size:reset";
"M-u" = "perl:url-select:select_next";
"M-C-n" = "perl:color-themes:next";
"M-C-p" = "perl:color-themes:prev";
"M-C-l" = "perl:color-themes:load-state";
"M-C-s" = "perl:color-themes:save-state";
#+end_src
******** Scrollbars
#+begin_src nix :noweb-ref urxvt-scroll
bar.enable = false;
#+end_src
******** Misc
#+begin_src nix :noweb-ref urxvt-extra
"geometry" = "128x32";
"perl-lib" = "${pkgs.rxvt-unicode}/lib/urxvt/perl";
"perl-ext-common" = builtins.concatStringsSep "," [
"default"
"font-size"
"url-select"
"color-themes"
];
"url-select.autocopy" = true;
"url-select.launcher" = "${pkgs.xsel-copy-url}/bin/xsel-copy-url";
"url-select.underline" = true;
"color-themes.themedir" = "${pkgs.vidbina-urxvt-themes}/share";
"color-themes.state-file" = "${config.home.homeDirectory}/.urxvt-theme";
"color-themes.autosave" = 1;
#+end_src
******** Themes
#+begin_src nix :noweb-ref linux-overlays
vidbina-urxvt-themes =
let
readTheme = x:
let
text = builtins.readFile (./. + "/Xresources.d/themes/${x}");
in
pkgs.writeTextDir "share/${x}" text;
in
pkgs.symlinkJoin {
name = "vidbina-urxvt-themes";
paths = map readTheme [
"vidbina-dark.Xresources"
"vidbina-light.Xresources"
];
};
#+end_src
******* autorandr
In order to simplify screen management, we can use the [[https://github.com/phillipberndt/autorandr/][autorandr]] utility.
For the first time using a configuration, we use the =arandr= utility to graphically align the screens in the formation that we want after which we can save and name the configuration using the following command (where =CONFIGNAME= is the name that we want to save the configuration as):
#+begin_src bash
autorandr --save CONFIGNAME
#+end_src
A configuration can be autoloaded by running the following command:
#+begin_src bash
autorandr --change
#+end_src
#+begin_quote
[!IMPORTANT]
⚠️ With the autorandr tool, we have to plug screens into the same ports as we used when configuring the setup. In the case of my newer laptop where I have a bunch of USB C ports with the risk of pluggin monitors in different configurations between docking attempts, I just connect the monitor in every likely configuration, configure my setup with =arandr= and then save it with =autorandr --save= to ensure that autorandr will have seen that configuration before. 😉
#+end_quote
#+begin_src nix :noweb-ref x-programs
programs.autorandr = {
enable = true;
};
#+end_src
******* slock
The [[https://tools.suckless.org/slock/][slock]] package is a simple X screen locker by the suckless.org team.
Installing slock through systemPackages causes the =unable to disable the OOM killer. Make sure to suid or sgid slock=, see https://nixos.wiki/wiki/Slock.
We therefore install slock in the nixos-configuration.
******** Autolock
#+begin_src nix :noweb-ref x-services
screen-locker = {
enable = true;
lockCmd = "/run/wrappers/bin/slock";
};
#+end_src
******* darkman
Use darkman to manage dark/light theme switching for GTK and Qt.
#+begin_src nix :noweb-ref x-packages
darkman
#+end_src
Run =darkman set light= or =darkman set dark= or just run =darkman toggle=.
******* TODO rofi
- State "TODO" from [2023-10-03 Tue 17:30] \\
Update config to work for Linux. common.nix is not used between darwin and linux and rofi is not relevant for darwin systems.
We import the previous rofi configuration and have removed the =programs.rofi.theme= option because Pywal is currently managing this.
#+begin_src nix :noweb-ref x-imports
./rofi/default.nix
#+end_src
******** TODO Fix the buggy theme setup
When producing the Rofi modals/prompts, we have some readability issues are some bits are not legible (dark text on dark bg).
****** Applets
#+begin_src nix :noweb-ref home-linux-services
services.blueman-applet.enable = true;
services.network-manager-applet.enable = true;
#+end_src
****** Gammastep
The next thing after redshift.
#+begin_src nix :noweb yes :noweb-ref home-linux-services
services.gammastep = {
enable = true;
<<home-linux-services-gammastep>>
temperature = {
# https://www.eizo.com/library/basics/color_temperature_on_an_LCD_monitor/
day = 6500;
night = 2500;
};
tray = true;
};
#+end_src
******* Berlin
#+begin_src nix :noweb-ref home-linux-services-gammastep
dawnTime = "5:00-6:00";
duskTime = "17:35-19:00";
latitude = 52.5;
longitude = 13.4;
#+end_src
******* COMMENT Bangkok
#+begin_src nix :noweb-ref home-linux-services-gammastep
dawnTime = "5:00-6:00";
duskTime = "17:35-19:00";
latitude = 13.7;
longitude = 100.5;
#+end_src
****** GPG Agent
#+begin_src nix :noweb-ref home-linux-services
services.gpg-agent = {
enable = true;
enableSshSupport = true;
};
#+end_src
****** Trayer
#+begin_src nix :noweb-ref home-linux-services
services.trayer = {
enable = true;
settings = {
align = "right";
alpha = 0;
edge = "top";
height = 20;
monitor = "primary";
tint = "0x00000000";
transparent = true;
width = 250;
widthtype = "pixel";
};
};
#+end_src
*** Common Configuration (Linux only)
#+begin_src nix :noweb yes :tangle common.nix
# Tangled from README.org
{ config, lib, pkgs, ... }:
# TODO: Config mutt
let
inherit (pkgs) stdenv;
pathIfExists = (p: if (builtins.pathExists p) then [ p ] else [ ]);
sources = import ./nix/sources.nix;
<<common-packages-let>>
in
{
imports = [
<<common-imports>>
]
++ (pathIfExists ./personal.nix);
home.packages = [
<<common-packages>>
<<desktop-packages>>
];
home.file = {
<<common-home-files>>
};
#home.file.".profile".text = ''
# PATH=${toString ./bin}:$HOME/.nix-profile/bin:$PATH
# export PATH
#'';
home.sessionPath = [
(toString ./bin)
];
nix = {
extraOptions = ''
experimental-features = nix-command flakes
'';
};
nixpkgs = {
overlays = [
(self: super: {
<<common-overlays>>
})
];
config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
<<nixpkgs-unfree>>
];
};
<<common-programs>>
}
#+end_src
#+begin_src nix :noweb-ref common-home-files
".config/ranger".source = config.lib.file.mkOutOfStoreSymlink ./ranger;
# TODO: Remove, likely not necessary
".direnvrc".source = config.lib.file.mkOutOfStoreSymlink ./direnv/direnvrc;
#+end_src
**** WIP Generalise config by removing home-manager specifics in common.nix and other suposedly shareable nix files and considering whether out concern specific nix-files introduce needless idirection
Linux vs darwin nix configurations will have different attributes/options that we can configure under =home.= due to home-manager vs nix-darwin being separate projects. As such, the notion of .nix files that we can share between the two platforms doesn't really make much sense. We're better of specifying MacOS (darwin) specifics and NixOS specifics inside of the respective application-level heading and tangling it into one flat config file per platform.
**** Common Programs
#+begin_src nix :noweb yes :noweb-ref common-programs
# Let Home Manager install and manage itself.
programs.home-manager.enable = true;
programs.direnv = {
enable = true;
nix-direnv = {
enable = true;
};
};
programs.tmux = {
enable = true;
extraConfig = builtins.readFile (./. + "/tmux.conf");
};
#+end_src
***** TODO Remove common
Common is an architectural mistake. There are bits that can be shared between Darwin and Linux systems, but we probably shouldn't use another level of indirection by introducing another file which we import between the system-specific configs. Writing directly into the target system's config is much cleaner and simpler to reason about.
**** Manual
Disabled because of validation errors.
#+begin_src text
error: builder for '/nix/store/1f5lhdhsj2lf090pbxbvpmp3nijmzpy6-manual-combined.drv' failed with exit code 3;
last 10 log lines:
> /nix/store/vlpr4h1k43rbr5gpb3zrphq8gn6l4n4l-manual-combined/manual-combined.xml:1336: element variablelist: Relax-NG validity error : Did not expect element variablelist there
> 1332 </section>
> 1333 </chapter>
> 1334 <appendix xml:id="ch-options">
> 1335 <title>Configuration Options</title>
> 1336 <variablelist xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="home-manager-options" xml:base="nmd-result/home-manager-options.xml"><varlistentry><term xlink:href="#opt-_module.args" xml:id="opt-_module.args"><option>_module.args</option></term><listitem><para/><para><emphasis>Type:</emphasis> lazy attribute set of raw value</para><para><emphasis>Declared by:</emphasis></para><simplelist><member><filename xlink:href="https://github.com/nix-community/home-manager/blob/master/lib/modules.nix#blob-path">
> 1337 <home-manager/lib/modules.nix>
> 1338 </filename></member></simplelist></listitem></varlistentry><varlistentry><term xlink:href="#opt-accounts.email.accounts" xml:id="opt-accounts.email.accounts"><option>accounts.email.accounts</option></term><listitem><para>List of email accounts.</para><para><emphasis>Type:</emphasis> attribute set of (submodule)</para><para><emphasis>Default:</emphasis> <literal>
>
> /nix/store/vlpr4h1k43rbr5gpb3zrphq8gn6l4n4l-manual-combined/manual-combined.xml fails to validate
#+end_src
#+begin_src nix :noweb-ref common-programs
manual = {
# Use `home-manager-help`
html.enable = false;
# Use `man home-configuration.nix`
manpages.enable = false;
};
#+end_src
**** Zsh
#+begin_src nix :noweb yes :noweb-ref common-programs
programs.zsh = {
enable = true;
enableAutosuggestions = false;
enableSyntaxHighlighting = true;
defaultKeymap = "viins";
initExtraBeforeCompInit = ''
<<zsh-init-before-compinit>>
'';
initExtra = ''
<<zsh-init-extra>>
'';
};
#+end_src
#+begin_src sh :noweb-ref zsh-init-before-compinit
setopt histignorespace # keeps lines preceded with SPACE out of history
setopt INTERACTIVE_COMMENTS # allow inline comments like this one
#+end_src
***** COMMENT Bindings
#+begin_src sh :noweb-ref zsh-init-extra
bindkey -v # use vim key bindings
source ${./zsh/keybindings.zsh}
source ${./zsh/functions.zsh}
#+end_src
***** Emacs-related Settings
****** COMMENT Emacs as Default Editor through zsh-init
Let's set Emacs up as our default editor by setting ~EDITOR~ and ~VISUAL~ such that the Emacs client is fired up when text needs to be edited.
#+begin_src sh :noweb-ref zsh-init-before-compinit
export EDITOR="emacsclient -c -a emacs"
export VISUAL="emacsclient -c -a emacs"
#+end_src
****** Vterm Configuration
Define helper functions to allow us to jump between prompts in vterm in Emacs.
******* Shell function: vterm_printf
See https://github.com/akermu/emacs-libvterm#shell-side-configuration
#+begin_src sh :noweb-ref zsh-init-before-compinit
# https://github.com/akermu/emacs-libvterm#directory-tracking-and-prompt-tracking
vterm_printf(){
if [ -n "$TMUX" ] && ([ "''${TERM%%-*}" = "tmux" ] || [ "''${TERM%%-*}" = "screen" ] ); then
# Tell tmux to pass the escape sequences through
printf "\ePtmux;\e\e]%s\007\e\\" "$1"
elif [ "''${TERM%%-*}" = "screen" ]; then
# GNU screen (screen, screen-256color, screen-256color-bce)
printf "\eP\e]%s\007\e\\" "$1"
else
printf "\e]%s\e\\" "$1"
fi
}
#+end_src
******** TODO Alter noweb-ref to something more general
For bash and zsh.
******* Prep for Elisp: vterm-clear-scrollback
See https://github.com/akermu/emacs-libvterm#vterm-clear-scrollback
#+begin_src sh :noweb-ref zsh-init-before-compinit
if [[ "$INSIDE_EMACS" = 'vterm' ]]; then
alias clear='vterm_printf "51;Evterm-clear-scrollback";tput clear'
fi
#+end_src
******* Prep for Elisp: vterm-buffer-name-string
See https://github.com/akermu/emacs-libvterm#vterm-buffer-name-string
#+begin_src bash
autoload -U add-zsh-hook
add-zsh-hook -Uz chpwd (){ print -Pn "\e]2;%m:%2~\a" }
#+end_src
******* Prompt Tracking
See https://github.com/akermu/emacs-libvterm#directory-tracking-and-prompt-tracking
#+begin_src sh :noweb-ref zsh-init-before-compinit
vterm_prompt_end() {
vterm_printf "51;A";
}
setopt PROMPT_SUBST
PROMPT="%K{205} %k%S%B↪%b%s %(?.%F{green}√.%F{red}%?)%f" # 256-color pink block (#FF5FAF) + standout ↪: two adjacent visual signals anchor the prompt in busy output
PROMPT="$PROMPT → %F{yellow}%~%f" # pwd
PROMPT="$PROMPT @ %F{magenta}%D{%Y.%m.%d} %B%F{blue}%T%f%b" # date/time
PROMPT="$PROMPT"$'\n'
PROMPT="$PROMPT%F{green}>%f " # prompt
PROMPT=$PROMPT'%{$(vterm_prompt_end)%}'
#+end_src
******** COMMENT Previous
#+begin_src sh :noweb-ref zsh-init-before-compinit
vterm_prompt_end() {
vterm_printf "51;A";
}
vterm_cmd() {
local vterm_elisp
vterm_elisp=""
while [ $# -gt 0 ]; do
vterm_elisp="$vterm_elisp""$(printf '"%s" ' "$(printf "%s" "$1" | sed -e 's|\\|\\\\|g' -e 's|"|\\"|g')")"
shift
done
vterm_printf "51;E$vterm_elisp"
}
vterm_prompt_end() {
vterm_printf "51;A$(whoami)@$(hostname):$(pwd)";
}
setopt PROMPT_SUBST
#PROMPT="↪ %(?.%F{green}√.%F{red}%?)%f" # error state
#PROMPT="$PROMPT → %F{yellow}%~%f" # pwd
#PROMPT="$PROMPT @ %F{magenta}%D{%Y.%m.%d} %B%F{blue}%T%f%b" # date/time
#PROMPT="$PROMPT"$'\n'
#PROMPT="$PROMPT%F{green}>%f" # prompt
PROMPT="$PROMPT$(vterm_prompt_end)" # for vterm (emacs)
#+end_src
******* Message Passing
See https://github.com/akermu/emacs-libvterm#message-passing
#+begin_src sh :noweb-ref zsh-init-before-compinit
vterm_cmd() {
local vterm_elisp
vterm_elisp=""
while [ $# -gt 0 ]; do
vterm_elisp="$vterm_elisp""$(printf '"%s" ' "$(printf "%s" "$1" | sed -e 's|\\|\\\\|g' -e 's|"|\\"|g')")"
shift
done
vterm_printf "51;E$vterm_elisp"
}
#+end_src
***** Completions
****** TODO Read up on completions for ideas
Read https://scriptingosx.com/2019/07/moving-to-zsh-part-5-completions/
****** Bash completions
#+begin_src sh :noweb-ref zsh-init-extra
# enable bash completion
autoload -U +X bashcompinit && \
bashcompinit
#+end_src
****** Color
The [[https://zsh.sourceforge.io/Doc/Release/Zsh-Modules.html#The-zsh_002fcomplist-Module][complist]] module allows completion lists to be color-coded.
#+begin_src sh :noweb-ref zsh-init-extra
zmodload -i zsh/complist
#source ${./zsh/zstyle.zsh}
#+end_src
****** Fzf completions
The fzf ([[https://github.com/junegunn/fzf][GitHub]]) fuzzy finder utility, is reported to be blazingly fast. It was commented out of the configuration a while back because of some memory-allocation issue way back but it is hard to live without any form of reverse search help in bash.
#+begin_src sh :noweb-ref zsh-init-extra
source ${pkgs.fzf}/share/fzf/completion.zsh
source ${pkgs.fzf}/share/fzf/key-bindings.zsh
#+end_src
#+begin_src text
fatal error: mallocgc called without a P or outside bootstrapping
runtime: panic before malloc heap initialized
#+end_src
****** gh completions
#+begin_src sh :noweb-ref zsh-init-extra
# enable gh completion
eval "$(gh completion -s zsh)"
#+end_src
**** Pywal: 🎨 Generate and change color-schemes on the fly
For Linux, we install pywal through the =programs= attribute:
#+begin_src nix :noweb yes :noweb-ref common-programs
programs.pywal = {
enable = true;
};
#+end_src
For Darwin, we currently install Pywal with home-manager:
#+begin_src nix :noweb-ref home-darwin-packages
pywal
#+end_src
** The more tedious and manual way: without home-manager
The tedious way basically requires one to make symlinks from the needed locations into this dotfiles repository. There are a number of ways how one can simplify this experience ranging from manually symlinking everything that you would need all the way up to using a home-manager alternative like GNU Stow to manage these symlinks for you (and minimize the toil on your end).
This is a listing of the symlinks that I could track in my home directory right before moving over to home-manager. I may have missed some, but largely this covers much of what I have packaged in this repository so it should be relatively complete.
#+begin_example
~/.Xmodmap -> ~/dotfiles/xmodmap
~/.coloritrc -> ~/dotfiles/colorit/coloritrc
~/.conkyrc -> ~/dotfiles/conky.conf
~/.emacs.d -> ~/dotfiles/emacs
~/.lein -> ~/dotfiles/lein
~/.octaverc -> ~/dotfiles/octave/.octaverc
~/.tmux.conf -> ~/dotfiles/tmux.conf
~/.xsession -> ~/dotfiles/xsession
~/.config/asciinema -> ~/dotfiles/asciinema
~/.config/ghorg -> ~/dotfiles/ghorg
~/.config/redshift.conf -> ~/dotfiles/redshift.conf
~/.config/rofi -> ~/dotfiles/rofi
~/.config/starship.toml -> ~/dotfiles/starship.toml
~/.config/termite -> ~/dotfiles/termite
~/.direnvrc -> ~/dotfiles/direnv/direnvrc
#+end_example
*** TODO direnv
#+begin_src bash
ln -s ${PATH_TO_DOTFILES}/direnv ${HOME}/.direnv
#+end_src
*** .xsession
:PROPERTIES:
:CUSTOM_ID: xsession
:END:
#+begin_src shell
ln -s ${PATH_TO_DOTFILES}/xsession ${HOME}/.xsession
#+end_src
- sets the background (I just set a background color, but use =feh= to
set a wallpaper)
- loads .Xmodmap to load custom keyboard bindings
- start WM
*** .Xresources.d
:PROPERTIES:
:CUSTOM_ID: xresources.d
:END:
#+begin_quote
⚠️ managed with nix home-manager?
#+end_quote
#+begin_src shell
ln -s ${PATH_TO_DOTFILES}/Xresources.d ${HOME}/.Xresources.d
#+end_src
*** .Xmodmap
:PROPERTIES:
:CUSTOM_ID: xmodmap
:END:
#+begin_src shell
ln -s ${PATH_TO_DOTFILES}/Xmodmap ${HOME}/.Xmodmap
#+end_src
- disables caps lock
- remaps tilde and grave to capslock+[shift]+z in an effort to minimise
finger travel (the macbook has a narrower left shift and places the
tilde/grave button between the left shift and the Z key)
*** Tmux
:PROPERTIES:
:CUSTOM_ID: tmux
:END:
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/tmux.conf ${HOME}/.config/tmux.conf
#+end_src
- sets up vi key bindings in tmux
- remaps colors
*** Termite
:PROPERTIES:
:CUSTOM_ID: termite
:END:
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/termite ${HOME}/.config/termite
#+end_src
*** Starship
:PROPERTIES:
:CUSTOM_ID: starship
:END:
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/starship.toml ${HOME}/.config/starship.toml
#+end_src
*** Rofi
:PROPERTIES:
:CUSTOM_ID: rofi
:END:
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/rofi ${HOME}/.config/rofi
#+end_src
*** Redshift
:PROPERTIES:
:CUSTOM_ID: redshift
:END:
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/redshift ${HOME}/.config/redshift
#+end_src
*** Ghorg
:PROPERTIES:
:CUSTOM_ID: ghorg
:END:
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/ghorg ${HOME}/.config/ghorg
#+end_src
*** TODO Compton
:PROPERTIES:
:CUSTOM_ID: todo-compton
:END:
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/compton/compton.conf ${HOME}/.config/compton.conf
#+end_src
*** Octave
:PROPERTIES:
:CUSTOM_ID: octave
:END:
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/octave/.octaverc ${HOME}/.config/.octaverc
#+end_src
*** Lein
:PROPERTIES:
:CUSTOM_ID: lein
:END:
Package manager and build tool for Clojure. The .lein dotfile lists
convenience plugins for development.
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/lein ${HOME}/.lein
#+end_src
*** Colorit
:PROPERTIES:
:CUSTOM_ID: colorit
:END:
https://linux.die.net/man/1/colorit
Colorit is a script for markup-ing text input which is used in my setup
by dict.
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/colorit/coloritrc ${HOME}/.coloritrc
#+end_src
*** Conky
:PROPERTIES:
:CUSTOM_ID: conky
:END:
https://github.com/brndnmtthws/conky
Conky is a system monitoring tool which allows the presentation of
system metrics in a GUI.
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/conky.conf ${HOME}/.conkyrc
#+end_src
*** Emacs
:PROPERTIES:
:CUSTOM_ID: emacs
:END:
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/emacs ${HOME}/.emacs.d
#+end_src
* Configuration
** Personal Details
For developer tooling, we define our =userName= and =userEmail= which we will rely on in configuring git, for example.
#+begin_src nix :noweb yes :noweb-ref home-darwin-programs-git-settings
user.name = "David Asabina";
# NOTE: We avoid setting userEmail in order to have the git CLI fail
# and explicitly ask for this when not set to avoid commits under
# wrong addresses.
# Recommendation: configure email on a per-folder basis, not globally.
#user.email = "vid@bina.me";
#+end_src
We all have parts of our configs that are for our eyes only and the
[[file:personal.nix]] file can be populated to contain sensitive and private
parts of your configuration. This home-configuration will load a
personal.nix file if found so the use of this file is optional (your
configuration should work without it).
Observe the snippet below for an example of a valid personal.nix file.
#+begin_src nix
{ config, pkgs, lib, options, ... }:
{
# Home Manager needs a bit of information about you and the
# paths it should manage.
home.username = "vidbina";
home.homeDirectory = "/home/vidbina";
# This value determines the Home Manager release that your
# configuration is compatible with. This helps avoid breakage
# when a new Home Manager release introduces backwards
# incompatible changes.
# You can update Home Manager without changing this value. See
# the Home Manager release notes for a list of state version
# changes in each release.
home.stateVersion = "21.05";
home.packages = [ ];
}
#+end_src
Note that the same configuration above is adapted for macOS by setting =home.homeDirectory= to a valid macOS home path like =/Users/vidbina=.
*** Configure user for MacOS
#+begin_src nix :noweb-ref nix-darwin
users.users.${username} = {
home = "/Users/${username}";
};
#+end_src
#+begin_src nix :noweb-ref darwin-system
primaryUser = username;
#+end_src
*** Machine Definitions
Machine-specific configuration lives in =machines.nix= which is
tangled from this file and imported directly by =flake.nix=.
#+begin_src nix :tangle machines.nix
# Per-machine configuration. Copy or symlink to machines.nix.
# This is the single place to configure user and path settings.
[
{
name = "berlin26-m5pro";
system = "aarch64-darwin";
username = "vidbina";
dotfilesPath = "/Users/vidbina/Code/vidbina/dotfiles";
extraModules = [
{
networking.hostName = "berlin26-m5pro";
ids.gids.nixbld = 350;
system.stateVersion = 5;
}
];
}
{
name = "tokyo23-m2";
system = "aarch64-darwin";
username = "vidbina";
dotfilesPath = "/Users/vidbina/Code/vidbina/dotfiles";
extraModules = [ ];
}
{
name = "berlin-4corei7";
system = "x86_64-darwin";
username = "vidbina";
dotfilesPath = "/Users/vidbina/Code/vidbina/dotfiles";
extraModules = [ ];
}
]
#+end_src
** nix-darwin
:PROPERTIES:
:header-args: :noweb-sep "\n\n"
:END:
On macOS, nix-darwin provides the most batteries included nix experience. We can manage services (through launchd), home-manager and homebrew all through a nix configuration.
#+begin_src nix :noweb yes :tangle configuration-darwin.nix
# Tangled from README.org
# This is a nix-darwin config
{ pkgs, lib, inputs, config, username, ... }:
with lib;
{
imports = [
# import modules into our nix-darwin config
<<nix-darwin-imports>>
./system/darwin
];
# List packages installed in system profile. To search by name, run:
# $ nix-env -qaP | grep wget
environment.systemPackages = with pkgs; [
# common Darwin packages
<<nix-darwin-packages-common>>
] ++ (if stdenv.hostPlatform.system == "aarch64-darwin" then [
# ARM-only packages
<<nix-darwin-packages-arm>>
] else [
# Intel-only packages
<<nix-darwin-packages-intel>>
]);
environment.interactiveShellInit = lib.strings.concatStrings [
<<nix-darwin-interactive-shellinit>>
];
# General nix-darwin settings
<<nix-darwin>>
}
#+end_src
*** Launchd
Read the Apple [[https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html][Daemons and Service Programming Guide]] for some basic information on how to work with launchd. Keep in mind that launchd isn't systemd and sucks in the sense that starting/stopping services doesn't seem to do the obvious things that their names imply and as one has grown familiar to with systemd.
Furthermore read https://www.launchd.info/ for more information on the launchd system. I have for a long time misunderstood it as an init system hut it is more of a job manager.
*** TODO Packages for MacOS
All packages that are architecture agnostic are installed in all of our macOS machines.
#+begin_quote
[!NOTE]
We want to move this block of package definitions into the appropriate sections such that all config details are localised to the tool-specific section in our config. This block here, is a hack because I couldn't figure out how to use the common.nix in my nix-darwin setup, so we're definitely not DRY in this configuration setup.
#+end_quote
#+begin_src nix :noweb-ref dev-packages
gh
gleam
gnumake
gnupg
gotop
html-tidy
htop
httpie
httplab
jq
kakoune
typescript-language-server
nodejs
pqrs
nixpkgs-fmt
redis
sqlite-interactive
tree
tree-sitter
vim
yq
#+end_src
Intel-only packages are listed separately such that we can use them on the macOS machine that still has a x86-based Intel chip but avoid trying to install them on ARM-based Apple machines.
**** COMMENT Intel-only MacOS Packages
#+begin_src nix :noweb-ref nix-darwin-packages-intel
# Darwin packages for Intel-only
gdb
#+end_src
#+begin_quote
[!NOTE]
It follows that the amount of Intel-only packages will decrease as developers make their applications more readily available (also for Apple Silicon).
#+end_quote
*** TODO Split up config into tooling section
- [X] Make the first snippets comment snippets (for explanation)
- [ ] move the code out to the tool-specific section.
*** Setup nix on Darwin
#+begin_src nix :noweb-ref nix-darwin :noweb yes
nix = {
enable = true;
package = pkgs.nix;
# Necessary for using flakes on this system.
settings = {
experimental-features = "nix-command flakes";
<<nix-darwin-settings>>
};
};
#+end_src
**** Trusted users on Darwin
#+begin_src nix :noweb-ref nix-darwin-settings
# Adding trusted users for devenv to use Cachix
trusted-users = [
"root"
username
];
#+end_src
*** Use gpg-agent on Darwin
SSH agent is handled by 1Password (via =IdentityAgent= in =~/.ssh/config=), so =enableSSHSupport= is disabled to avoid =SSH_AUTH_SOCK= pointing at a stale gpg-agent socket that conflicts with the 1Password agent.
#+begin_src nix :noweb-ref nix-darwin
programs.gnupg.agent = {
enable = true;
enableSSHSupport = false;
};
#+end_src
Install =pinentry-mac= for the native macOS GPG passphrase dialog:
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"pinentry-mac"
#+end_src
*** Setup zsh on Darwin
#+begin_src nix :noweb-ref nix-darwin
# Create /etc/zshrc that loads the nix-darwin environment.
# NOTE: Copied from common.nix
programs.zsh = {
enable = true; # default shell on catalina
enableSyntaxHighlighting = true;
# Used to be initExtraBeforeCompInit
# in nix-darwin, interactiveShellInit is called before compinit
# see https://github.com/LnL7/nix-darwin/blob/80bb201f4925cdda5a7a3c7b1900fb26bb2af2e8/modules/programs/zsh/default.nix#L168-L176
promptInit = ''
setopt histignorespace # keeps lines preceded with SPACE out of history
setopt INTERACTIVE_COMMENTS # allow inline comments like this one
# https://github.com/akermu/emacs-libvterm#directory-tracking-and-prompt-tracking
vterm_printf(){
if [ -n "$TMUX" ] && ([ "''${TERM%%-*}" = "tmux" ] || [ "''${TERM%%-*}" = "screen" ] ); then
# Tell tmux to pass the escape sequences through
printf "\ePtmux;\e\e]%s\007\e\\" "$1"
elif [ "''${TERM%%-*}" = "screen" ]; then
# GNU screen (screen, screen-256color, screen-256color-bce)
printf "\eP\e]%s\007\e\\" "$1"
else
printf "\e]%s\e\\" "$1"
fi
}
if [[ "$INSIDE_EMACS" = 'vterm' ]]; then
alias clear='vterm_printf "51;Evterm-clear-scrollback";tput clear'
fi
vterm_prompt_end() {
vterm_printf "51;A";
}
setopt PROMPT_SUBST
PROMPT="%K{205} %k%S%B↪%b%s %(?.%F{green}√.%F{red}%?)%f" # 256-color pink block (#FF5FAF) + standout ↪: two adjacent visual signals anchor the prompt in busy output
PROMPT="$PROMPT → %F{yellow}%~%f" # pwd
PROMPT="$PROMPT @ %F{magenta}%D{%Y.%m.%d} %B%F{blue}%T%f%b" # date/time
PROMPT="$PROMPT"$'\n'
PROMPT="$PROMPT%F{green}>%f " # prompt
PROMPT=$PROMPT'%{$(vterm_prompt_end)%}'
vterm_cmd() {
local vterm_elisp
vterm_elisp=""
while [ $# -gt 0 ]; do
vterm_elisp="$vterm_elisp""$(printf '"%s" ' "$(printf "%s" "$1" | sed -e 's|\\|\\\\|g' -e 's|"|\\"|g')")"
shift
done
vterm_printf "51;E$vterm_elisp"
}
# Workaround to open new tab at pwd
# See https://apple.stackexchange.com/a/340778
# http://superuser.com/a/315029/4952
# Set Apple Terminal.app to resume directory... still necessary 2018-10-26
if [[ $TERM_PROGRAM == "Apple_Terminal" ]] && [[ -z "$INSIDE_EMACS" ]] {
function chpwd {
local SEARCH=' '
local REPLACE='%20'
local PWD_URL="file://$HOSTNAME''${PWD//$SEARCH/$REPLACE}"
printf '\e]7;%s\a' "$PWD_URL"
}
chpwd
}
# Use vim bindings in zsh
bindkey -v
# https://unix.stackexchange.com/a/30169
bindkey '^R' history-incremental-search-backward
'';
};
#+end_src
*** Configure Darwin system
#+begin_src nix :noweb-ref nix-darwin :noweb yes
# Set Git commit hash for darwin-version.
system = {
configurationRevision = inputs.self.rev or inputs.self.dirtyRev or null;
keyboard.enableKeyMapping = true;
keyboard.remapCapsLockToControl = true;
# Used for backwards compatibility, please read the changelog before changing.
# $ darwin-rebuild changelog
stateVersion = mkDefault 4;
<<darwin-system>>
};
#+end_src
**** macOS Defaults
Observe https://macos-defaults.com for information on how to manage macOS declaratively. The =default= command can be used to review the configuration.
***** Key Press
On a system level, we want continued key presses to register as repeat presses so we can leverage this for easy navigation (using keys like j, k, l, m). Some terminals, like Ghostty manage this separately, but other tools may not have a settings for this, in which the system-wide setting helps. We set [[https://macos-defaults.com/keyboard/applepressandholdenabled.html][ApplePressAndHoldEnabled]] to false in order to to accomplish this.
#+begin_src nix :noweb-ref darwin-system
defaults.NSGlobalDomain.ApplePressAndHoldEnabled = false;
#+end_src
We can review =NSGlobalDomain= settings with the following command:
#+begin_src bash
default read NSGlobalDomain
#+end_src
***** Force Click
Force click on macOS causes this annoying behavior where hard presses (single finger) open the dictionary as part of a /Look Up/. This can be disabled in the System Settings by looking up the Trackpad and turning the /Look up & data detectors/ setting off.
We explored the Trackpad settings https://macos-defaults.com/trackpad/firstclickthreshold.html while configuring Look Up to work only on a 3-finger press and attempt to declaratively set it through the trackpad and AppleMultitouchTrackpad settings.
#+begin_src nix :noweb-ref darwin-system
defaults.CustomUserPreferences = {
"com.apple.trackpad" = {
forceClick = false;
};
"com.apple.AppleMultitouchTrackpad" = {
TrackpadThreeFingerTapGesture = 2;
};
};
#+end_src
***** Displays have separate Spaces
To simplify working with apps in full screen, it is easiest if displays have their own spaces such that we can manage displays in isolation. This means no longer full-screening all displays to blank when a single display needs to present 1 app in full-screen mode.
#+begin_src nix :noweb-ref darwin-system
defaults.CustomUserPreferences = {
"com.apple.spaces" = {
"spans-displays" = false;
};
};
#+end_src
**** COMMENT Configure Darwin system activation scripts
#+begin_src nix :noweb-ref darwin-system
# Use activation scripts to set up Spotlight visibility of nix-darwin apps
# See https://github.com/LnL7/nix-darwin/issues/214#issuecomment-1230730292
activationScripts.applications.text = lib.mkForce ''
echo "setting up ~/Applications..." >&2
applications="$HOME/Applications"
nix_apps="$applications/Nix Apps"
# Needs to be writable by the user so that home-manager can symlink into it
if ! test -d "$applications"; then
mkdir -p "$applications"
chown ${username}: "$applications"
chmod u+w "$applications"
fi
# Delete the directory to remove old links
rm -rf "$nix_apps"
mkdir -p "$nix_apps"
find ${config.system.build.applications}/Applications -maxdepth 1 -type l -exec readlink '{}' + |
while read src; do
# Spotlight does not recognize symlinks, it will ignore directory we link to the applications folder.
# It does understand MacOS aliases though, a unique filesystem feature. Sadly they cannot be created
# from bash (as far as I know), so we use the oh-so-great Apple Script instead.
/usr/bin/osascript -e "
set fileToAlias to POSIX file \"$src\"
set applicationsFolder to POSIX file \"$nix_apps\"
tell application \"Finder\"
make alias file to fileToAlias at applicationsFolder
# This renames the alias; 'mpv.app alias' -> 'mpv.app'
set name of result to \"$(rev <<< "$src" | cut -d'/' -f1 | rev)\"
end tell
" 1>/dev/null
done
'';
#+end_src
*** Setup homebrew
Configure homebrew:
#+begin_src nix :noweb-ref nix-darwin :noweb yes
homebrew = {
enable = true;
global = {
autoUpdate = true; # same as default
};
onActivation = {
autoUpdate = false; # same as default
# run `brew update` manually when adding new casks
cleanup = "uninstall";
extraFlags = [
"--verbose"
];
upgrade = false; # same as default
};
taps = [
<<homebrew-taps>>
];
brews = [
<<homebrew-brews>>
];
casks = builtins.filter (x: x != null) [
<<homebrew-casks>>
];
masApps = {
<<homebrew-masapps>>
};
enableZshIntegration = true;
};
#+end_src
As outlined in [[https://apple.stackexchange.com/a/125471][this StackExchange answer]], brew prefers pre-compiled binaries (so called /bottles/). CLI tools are typically installed through the standard homebrews **brews** facility as demonstrated through the following snippet:
#+begin_src nix
,#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"smudge/smudge/nightlight"
,#+end_src
#+end_src
Graphical tools which are typically installed through the /drag icon to Applications/ mess, can be installed in a more automated fashion through the use of the homebrew casks extension as demonstrated by the following snippet that we can use in our literate config where needed:
#+begin_src nix
,#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"raycast"
,#+end_src
#+end_src
Install apps from the Apple App Store through the mas CLI tool for which the nix-darwin homebrew config provides the [[https://daiderd.com/nix-darwin/manual/index.html#opt-homebrew.masApps][=masApps= attribute]].
💡 Remember to go through the list of all masApps in your file:configuration-darwin.nix and make sure to at least manually install them into your Apple account once to avoid the [[*Resolve: Redownload Unavailable with This Apple ID: This redownload is not available for this Apple ID either because it was bought by a different user or the item was refunded or cancelled.][this "Redownload Unavailable with this Apple ID" issue]].
You can use the =mas search= command to find available apps from the Apple App Store:
#+begin_src bash
mas search SOMETHING
#+end_src
*** DONE Resolve: Redownload Unavailable with This Apple ID: This redownload is not available for this Apple ID either because it was bought by a different user or the item was refunded or cancelled.
Apps need to already be in a user's Purchased list before mas can install them. For any new tools, just make sure that you install it on one machine at least manually in order to add it to your Purchased list as documented in [[https://github.com/mas-cli/mas/issues/85#issuecomment-305382347][GH mas-cli issue 85]]. In my case, I didn't even complete the installation, I just started it to add it to the list and then prematurely stopped it in order to continue the installation through nix-darwin.
Keep in mind to authorize your device as documented in https://support.apple.com/en-us/HT201251 and which can be done through the following steps:
- Open Apple Music
- Navigate to Account > Authorisations > Authorise this computer
- provide credentials to Apple account.
You can review your current computer's authorisation status by opening the App Store app and opening the Account Settings modal.
Computer authorisation status did not have any bearing on this issue but it seems a good practice to ocassionally verify that all the authorised devices in an account are still in your possession.
*** nix-darwin nixpkgs
**** Allow some unfree packages in nix-darwin
#+begin_src nix :noweb-ref nix-darwin :noweb yes
nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
<<darwin-unfree>>
];
#+end_src
**** Allow some nixpkgs overlays in nix-darwin
#+begin_src nix :noweb-ref nix-darwin :noweb yes
nixpkgs.overlays = [
<<darwin-overlays>>
];
#+end_src
** Editors
*** VsCode
Visual Studio Code is unfree software and needs to be added to the list of unfree packages that we want to tolerate:
#+begin_src nix :noweb-ref darwin-unfree
"vscode"
#+end_src
Our vscode configuration declaratively manages soem extensions, keybindings and user settings:
#+begin_src nix :noweb yes :noweb-ref home-darwin
programs.vscode = {
enable = true;
profiles.default = {
extensions = with pkgs.vscode-marketplace; [
<<vscode-extensions>>
];
keybindings = [
<<vscode-keybindings>>
];
userSettings = {
<<vscode-settings>>
};
};
};
#+end_src
**** COMMENT VsCode Extensions
As per <2025-12-16 Tue>, we're disabling Nix-managed VSCode extensions due to persistent build issues.
**Issues encountered:**
- Unfree license problems with Claude Code/ChatGPT extensions (despite proper allowUnfree configuration)
- ZIP unpacking failures with multiple extensions (be5invis.toml, bierner.github-markdown-preview)
- Build failures persist even with updated nix-vscode-extensions flake and proper nixpkgs follows configuration
- The nix-vscode-extensions flake has inherent build reliability issues
**Decision:** Install VSCode extensions manually through the marketplace for better reliability and automatic updates.
VSCode program itself still managed declaratively with settings and keybindings.
We get our vscode extensions from the nix-community nix-vscode-extensions package which we alias to the reference =my-vscode-extensions= for internal use:
#+begin_src nix :noweb-ref darwin-overlays
inputs.vscode-extensions.overlays.default
#+end_src
The extensions that we are interested in are the following:
#+begin_src nix :noweb-ref vscode-extensions
bbenoist.nix
be5invis.toml
elmtooling.elm-ls-vscode # depends on hbenl.vscode-test-explorer
hbenl.vscode-test-explorer
ms-vscode.test-adapter-converter
hediet.vscode-drawio
mkhl.direnv
ms-azuretools.vscode-docker
ms-playwright.playwright
ms-python.python
tomoki1207.pdf
vscodevim.vim
opentofu.vscode-opentofu
dart-code.flutter
#+end_src
***** COMMENT GitHub CoPilot in VSCode
#+begin_src nix :noweb-ref vscode-extensions
github.copilot
github.copilot-chat
#+end_src
#+begin_src nix :noweb-ref darwin-unfree
"vscode-extension-github-copilot"
#+end_src
***** COMMENT Remote Containers in VSCode
#+begin_src nix :noweb-ref vscode-extensions
ms-vscode-remote.remote-containers
#+end_src
#+begin_src nix :noweb-ref darwin-unfree
"vscode-extension-ms-vscode-remote-remote-containers"
#+end_src
***** Markdown Preview in VSCode
See [[https://marketplace.visualstudio.com/items?itemName=bierner.github-markdown-preview][Matt Bierner's Markdown extensions]] for useful upgrades to VsCodes Markdown Preview capabilities. Just open the regular markdown preview through the command palette (cmd+shift+p on MacOS).
We're installing them all:
#+begin_src nix :noweb-ref vscode-extensions
bierner.github-markdown-preview
bierner.markdown-checkbox
bierner.markdown-yaml-preamble
bierner.markdown-emoji
bierner.markdown-mermaid
bierner.markdown-footnotes
bierner.markdown-preview-github-styles
#+end_src
and enabling front-matter preview rendering in the config:
#+begin_src nix :noweb-ref vscode-settings
# https://marketplace.visualstudio.com/items?itemName=bierner.github-markdown-preview
"markdown.previewFrontMatter" = "show";
#+end_src
***** COMMENT Markdown Preview Enhanced in VSCode
See [[https://marketplace.visualstudio.com/items?itemName=shd101wyy.markdown-preview-enhanced][Yiyi Wang's Markdown Preview Enchanced]] to preview markdown with more batteries included. Use the command palette and search for *Markdown Preview Enhanced* commands. I have disabled this because it doesn't do dark-mode well and that was more disruptive than not having callouts (as is the shortcoming of the standard previewer even with the Bierner extensions).
#+begin_src nix :noweb-ref vscode-extensions
shd101wyy.markdown-preview-enhanced
#+end_src
***** COMMENT Org-mode in VsCode
On <2025-02-16 Sun>, I'm trying to rebuild my config and finding that this extension is no longer available through [[https://github.com/nix-community/nix-vscode-extensions?tab=readme-ov-file][vscode-extensions]], so I'm commenting it out for now.
#+begin_src nix :noweb-ref vscode-extensions
vscode-org-mode.org-mode
#+end_src
***** Show tree of TODO and FIXME comment
Outline comment tags like =TODO= and =FIXME= in a todo tree for quick access.
#+begin_src nix :noweb-ref vscode-extensions
gruntfuggly.todo-tree
#+end_src
**** VsCode Keybindings
The keybindings that we want are as follows:
#+begin_src nix :noweb-ref vscode-keybindings
{
"key" = "ctrl+tab";
"command" = "workbench.action.nextEditorInGroup";
}
{
"key" = "ctrl+shift+tab";
"command" = "workbench.action.previousEditorInGroup";
}
#+end_src
**** VsCode Settings
Define parts of the VsCode-specific fields are defined in the JSON format as follows:
#+begin_src nix :noweb-ref vscode-settings
"editor.cursorSurroundingLines" = 8;
# https://code.visualstudio.com/docs/editor/extension-marketplace#_can-i-stop-vs-code-from-providing-extension-recommendations
"extensions.ignoreRecommendations" = true;
# https://code.visualstudio.com/docs/editor/extension-marketplace#_can-i-stop-vs-code-from-providing-extension-recommendations
"telemetry.telemetryLevel" = "off";
"vim.highlightedyank.enable" = true;
"window.autoDetectColorScheme" = true;
# Make the time-out a bit longer to allow for us to get that direnv stuff done
"application.shellEnvironmentResolutionTimeout" = 20; # original was 10
#+end_src
***** Colored guides in VSCode
#+begin_src nix :noweb-ref vscode-settings
# https://www.roboleary.net/2021/11/06/vscode-you-dont-need-that-extension2.html#3-indentation-guides-colorization
"editor.guides.bracketPairs" = true;
"editor.guides.highlightActiveIndentation" = true;
#+end_src
***** Theme configuration in VSCode
#+begin_src nix :noweb-ref vscode-settings
"workbench.preferredDarkColorTheme" = "Dark 2026";
"workbench.preferredLightColorTheme" = "Light 2026";
#+end_src
***** Disable single click previews
Pressing a file with a single click to get a preview tab is really annoying because another click may just replace the previous /preview/ file. I'd much rather just double-click to open files in their dedicated tabs and then do housekeeping later. Makes things a bit more explicit. See [[https://stackoverflow.com/a/48559054][StackOverflow]] for more.
#+begin_src nix :noweb-ref vscode-settings
"workbench.list.openMode" = "doubleClick";
#+end_src
*** COMMENT Kakoune
#+begin_src nix :noweb-ref dev-packages
kakoune
#+end_src
*** Zed
[[https://zed.dev/][Zed]] is shaping up to be one of the coolest new editors. An IDE that was designed with speed in mind and should be blazingly fast with decent LLM features, multiplayer support and coming from the makers of Atom (from which they learned key lessons about how to not build and editor) and Treesitter. At least, that's what I get from their website and videos.
**** Install Zed from a homebrew cask
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"zed"
#+end_src
**** COMMENT Install Zed from Nixpkgs
#+begin_src nix :noweb-ref dev-packages
pkgs.zed-editor
#+end_src
*** Cursor
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"cursor"
#+end_src
** Version Control
*** Jujutsu
Just watched https://www.youtube.com/watch?v=2otjrTzRfVk&t=534s and am trying to get on the jj bandwagon to taste its benefits:
#+begin_src nix :noweb-ref dev-packages
pkgs.jujutsu
#+end_src
*** Git
:MANUAL:
<<manual-git>>
Configure your gitconfig by symlinking the [[file:gitconfig]] file in this repository into the home directory.
#+begin_src shell
ln -s ./git/gitconfig ~/gitconfig
#+end_src
The global excludes file defaults to =./config/git/ignore= so we're linking our ignore go-to into this path for convenience.
#+begin_src shell
ln -s ./git/ignore ~/.config/git/ignore
#+end_src
:END:
#+begin_src nix :noweb yes :noweb-ref home-darwin-programs
git = {
enable = true;
<<home-darwin-programs-git>>
settings = {
<<home-darwin-programs-git-settings>>
};
};
#+end_src
**** Gitignore
***** COMMENT Copied gitignore
#+begin_src nix :noweb-ref home-darwin-home-file
".config/git/ignore".source = ./git/ignore;
#+end_src
***** Global Gitignore
For convenience we define [[file:git/ignore]] which we want to automatically honor in every repo. Based on the instructions in =man gitignore= we stub the =XDG_HOME_CONFIG/.config/git/ignore= and the =~/.gitignore= files to reflect the content of [[file:git/ignore]].
#+begin_src nix :noweb-ref home-darwin-home-file
# Set global gitignore
".config/git/ignore".source = config.lib.file.mkOutOfStoreSymlink ./git/ignore;
#+end_src
#+begin_comment
Note that the =programs.git.ignores= setting in home manager can not coexist with the =home.file.".config/git/ignore"= home-manager option. I'm opting for the =home-file= approach since this simplifies updates to merely copying the output of the [[https://www.toptal.com/developers/gitignore][Toptal gitignore generator]]. 😉
#+end_comment
**** Git LFS
We want LFS enabled.
#+begin_src nix :noweb-ref home-darwin-programs-git
lfs.enable = true;
#+end_src
**** Git Aliases
#+begin_src nix :noweb-ref home-darwin-programs-git-settings
alias = {
wdiff = "diff --word-diff --word-diff-regex='\\w+'";
glog = "!git log --graph --all --format='%C(auto)%h %s%d' --color=always \"$@\" | gref-dedup | less -RF #";
ready = "!git checkout main && git pull --ff-only";
# Touch ID-free aliases for remote/agent sessions
mcommit = "-c commit.gpgsign=false commit";
mpush = "!git -c url.\"https://github.com/\".pushInsteadOf=\"git@github.com:\" push \"$@\" #";
mpull = "!git -c url.\"https://github.com/\".insteadOf=\"git@github.com:\" pull \"$@\" #";
};
#+end_src
**** gref-dedup
[[file:gref-dedup/src/main.rs][gref-dedup]] is a local Rust filter that deduplicates remote-prefix segments in
=git log --decorate= output. When a commit is annotated with both =origin/vidbina/foo=
and =vidbina/foo=, it collapses them to =[origin/]vidbina/foo= — the remote prefix
in dim text, the canonical branch path in normal color.
The =glog= zsh function (defined in [[file:zsh/functions.zsh]]) pipes =git glog= through
=gref-dedup= and =less -RF=, combining the existing alias with deduplication and paging.
#+begin_src nix :noweb-ref home-darwin-packages
(rustPlatform.buildRustPackage {
pname = "gref-dedup";
version = "0.1.0";
src = ./gref-dedup;
# Run `nix build .#packages.aarch64-darwin.default 2>&1 | grep 'got:'` to compute.
cargoHash = "sha256-MH3+teduU3ZQU9ZEMhxST8G0WOrxUqVoLdPEnYK8iws=";
})
#+end_src
**** Git Extra Configuration
Let's opt for naming our default branch "main", using nvim as our editor, using gpg2 are our GPG tool and setting git up to [[https://git-scm.com/docs/git-send-email][send patches by mail]].
#+begin_src nix :noweb yes :noweb-ref home-darwin-programs-git-settings
init = {
defaultBranch = "main";
};
core = {
editor = "nvim";
};
gpg = {
program = "gpg2";
};
sendemail = {
annotate = true;
smtpServer = "msmtp";
smtpServerOption = "-a vidbina";
};
#+end_src
***** WIP Explore =signing.format= setting for git
Observe the [[https://nix-community.github.io/home-manager/options.xhtml#opt-programs.git.signing.format][=git.signing.format=]] configuration options and note that with our current use of 1Password ssh signing, we should likely default to using ssh keys to sign commits. Hopefully this fixes the issue where git logs didn't reflect signing state of commits correctly.
#+begin_src nix :noweb-ref home-darwin-programs-git
signing.format = "ssh";
#+end_src
***** Colors in Git
For readability's sake, we set the colors that we display git diffs, greps and status payloads in.
#+begin_src nix :noweb-ref home-darwin-programs-git-settings
color = {
ui = true;
diff = {
meta = "yellow bold";
frag = "magenta bold";
old = "red";
new = "green";
};
grep = {
match = "yellow";
filename = "blue";
linenumber = "brightblack";
};
status = {
added = "yellow";
changed = "green";
untracked = "brightblack";
};
};
#+end_src
Since we are using pywal to sync terminal themes with Emacs, we set some baseline colors in git to harmonise these.
**** TODO COMMENT Diff: Look into delta or difftastic
#+begin_src nix :noweb-ref home-darwin-programs-git
delta = {
enable = true;
};
#+end_src
[2024-02-19 Mon] Note that difftastic use in a devenv resulted in outputs where some code keywords were highlighted in the same color as the terminal background and thus rendered visually invisible. Use of difftastic would likely require some customization of the used colorscheme in order for this to work.
#+begin_src nix :noweb-ref home-darwin-programs-git
difftastic = {
enable = true;
};
#+end_src
**** GitHub
#+begin_src nix :noweb-ref dev-packages
pkgs.gh
#+end_src
***** GitHub Copilot CLI
[[https://formulae.brew.sh/cask/copilot-cli][copilot-cli]] provides the =gh copilot= extension as a standalone binary. We install it via Homebrew cask rather than =gh extension install github/gh-copilot= (imperative) or nix (nix unstable trails at 1.0.44 vs latest 1.0.48; nixpkgs 25.11 is even further back at 0.0.362). After the next =darwin-rebuild switch=, =gh copilot= will be available on PATH.
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"copilot-cli"
#+end_src
**** GitLab
#+begin_src nix :noweb-ref dev-packages
pkgs.glab
#+end_src
** Utils
*** Android
**** Android File Transfer
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"android-file-transfer"
#+end_src
*** Coreutils
Sometimes we need GNU CLI utils, such as for dired in Emacs which expects the GNU ls variant which offers the =--dired= option. Install [[https://formulae.brew.sh/formula/coreutils][coreutils]] coreutils for this capability and note that for all utils that already have MacOS-native equivalents the GNU-equivalent will be prefixed with =g= such that the GNU =ls= tool is now accessed through =gls=:
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"coreutils"
#+end_src
*** Windows Utils
In order to build windows installation disks, we may need the wimlib util from time to time. See [[https://gist.github.com/acarril/8c15f600cf0397dd61161a470f50f669][acarril/bootable-win-on-mac gist]] for an example on how to build a Windows installation disk from MacOS.
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"wimlib"
#+end_src
*** Package Managers
**** Micromamba
Micromamba is a statically-linked build of /[[https://github.com/mamba-org/mamba][Mamba]]/, the C++ rewrite of Conda, which was written in Python and is known to be pretty slow. Micromamba has everything it needs it its executable. No dynamic deps.
#+begin_quote
<2025-05-09 Fri> Would be nice if we could just use a devenv, flake or nix-shell but because of glibc, it will be a bit tricky to build this for darwin.
#+end_quote
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"micromamba"
#+end_src
See [[https://mamba.readthedocs.io/en/latest/installation/micromamba-installation.html][installation instructions]] for additional guidance.
*** Development Environments
**** Direnv
#+begin_src nix :noweb yes :noweb-ref home-darwin-programs
direnv = {
enable = true;
nix-direnv = {
enable = true;
};
};
# NOTE: Enabling zsh also in hm in order to bring direnv bootstrap into scope
# See https://gist.github.com/jmatsushita/5c50ef14b4b96cb24ae5268dab613050?permalink_comment_id=4205285#gistcomment-4205285
zsh.enable = true;
#+end_src
**** Project .envrc
When a project provides a =flake.nix= with a =devShells.default=, a
one-line =.envrc= enables automatic shell activation on =cd= via direnv
+ nix-direnv:
#+begin_src bash :tangle .envrc
use flake
#+end_src
**Why this is safe to track.** A =use flake= directive is a declarative
tooling instruction — comparable to a =Makefile= or =.tool-versions=.
It contains no secrets and is idempotent. The overwhelming majority of
the Nix ecosystem (4 700+ repos on GitHub) commits these files. The
=direnv allow= gate ensures no =.envrc= runs without explicit opt-in.
**Secrets belong elsewhere.** If a project needs environment variables
with sensitive values (API keys, database URLs), put them in
=.envrc.local= or =.env= and add those to the project's =.gitignore=.
Never put secrets in =.envrc=.
**** Devenv
Pinned via flake input to get ahead of nixpkgs (which lags behind).
The =inputs= argument is passed through =extraSpecialArgs= in =flake.nix=.
#+begin_src nix :noweb-ref dev-packages
inputs.devenv.packages.${pkgs.system}.devenv
#+end_src
**** Xcode
On MacOS, we need [[https://apps.apple.com/de/app/xcode/id497799835?l=en-GB&mt=12][Xcode]] installed to do things like natively compile C/C++ code.
#+begin_src nix :noweb-ref homebrew-masapps :noweb yes
"Xcode" = 497799835;
#+end_src
One practical example of why we needed Xcode is outlined in https://stackoverflow.com/questions/22752000/clang-cmath-file-not-found which outlines how something like the following may not work because of libs not being available (in scope):
#+begin_src cpp
#include <cmath>
#+end_src
After installation, remember to run the following:
#+begin_src bash
sudo xcodebuild -license accept
#+end_src
*** Password Managers
**** COMMENT Pass
Replaced by 1Password. The =pass= CLI and its GPG-based workflow are no longer in use.
#+begin_src nix :noweb-ref nix-darwin-packages-common
pass
#+end_src
**** COMMENT Bitwarden
For FLOSS friendly password managers with better GUIs, Bitwarden can be your friend. See this interesting [[https://www.reddit.com/r/Bitwarden/comments/15ssebq/bitwarden_vs_1password/][Reddit thread]] that highlights some differences to 1password in 2023.
***** COMMENT Install Bitwarden with Nix
Note, bitwarden as packaged for nix is only availalble for the linux platform, not darwin.
#+begin_src nix :noweb-ref nix-darwin-packages-common
bitwarden-cli
bitwarden-desktop
#+end_src
***** COMMENT Install Bitwarden on MacOS from homebrew cask
#+begin_src nix :noweb-ref homebrew-casks
"bitwarden"
#+end_src
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"bitwarden-cli"
#+end_src
***** Install Bitwarden from Apple App Store
#+begin_src nix :noweb-ref homebrew-masapps :noweb yes
"Bitwarden" = 1352778147;
#+end_src
**** 1Password
#+begin_quote
[!WARNING]
On <2025-01-23 Thu> the nixpkgs for 1Password are [[https://github.com/NixOS/nixpkgs/blob/a8a41134c89e5f42a422e7e1cb929f5d21e09caa/pkgs/applications/misc/1password-gui/default.nix#L63-L64][marked as /broken/]] due some issue with having to be installed in =/Application/= which nix can't help us solve in an elegant manner as we'd have to refer to some obscure =/nix/store= path in our config.
#+end_quote
****** COMMENT Install 1Password with Nix
#+begin_src nix :noweb-ref nix-darwin-packages-common
_1password-gui
#+end_src
#+begin_src nix :noweb-ref darwin-unfree
"1password"
"_1password-gui"
#+end_src
***** Install 1Password on MacOS from homebrew cask
We install 1Password from homebrew to bring in version 8 into scope since the App Store only lists version 1 as per <2024-12-27 Fri>.
#+begin_src nix :noweb-ref homebrew-casks
"1password"
#+end_src
Additionally, we also install the 1Password CLI:
#+begin_src nix :noweb-ref homebrew-casks
"1password-cli"
#+end_src
***** Install 1Password for Safari from Apple App Store
The 1Password extension for Safari is available from the [[https://apps.apple.com/de/app/1password-for-safari/id1569813296?l=en-GB&mt=12][Apple App Store]]:
#+begin_src nix :noweb-ref homebrew-masapps :noweb yes
"1Password for Safari" = 1569813296;
#+end_src
***** COMMENT Install 1Password from Apple App Store
#+begin_quote
[!WARNING]
On <2024-12-26 Thu> the App Store app only installs 1Password version 7 on my berlin-4corei7 machine while homebrew installs version 8.
#+end_quote
1Password from the [[https://apps.apple.com/de/app/1password-7-password-manager/id1333542190?l=en-GB&mt=12][Apple App Store]] should have better access to security features on MacOS than the homebrew installed version, so we're opting for app store where we can.
#+begin_src nix :noweb-ref homebrew-masapps :noweb yes
"1Password" = 1333542190;
#+end_src
*** Terminals
**** DONE Alacritty
#+begin_src nix :noweb-ref dev-packages
alacritty
#+end_src
**** WezTerm
[[https://wezfurlong.org/wezterm][WezTerm]] is a terminal emulator and multiplexer written in Rust, with hyperlink support, emoji support and since it's written in Rust... probably as blazingly fast as it gets.
***** COMMENT Install WezTerm from homebrew cask
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"wezterm"
#+end_src
***** Install through Nix
#+begin_src nix :noweb-ref dev-packages
wezterm
#+end_src
***** WezTerm Lua Config
On nix-darwin, we load our WezTerm config from our dotfiles as follows:
#+begin_src nix :noweb-ref home-darwin-home-file
".wezterm.lua".source = ./wezterm/wezterm.lua;
#+end_src
#+begin_src lua :noweb yes :tangle wezterm/wezterm.lua
-- Tangled from README.org
local wezterm = require 'wezterm'
local config = {}
<<wezterm-config>>
return config
#+end_src
***** Theme selection based on system dark-mode status
We stub our WezTerm config to help with some theme-switching magic.
#+begin_src lua :noweb-ref wezterm-config
-- wezterm.gui is not available to the mux server, so take care to
-- do something reasonable when this config is evaluated by the mux
function get_appearance()
if wezterm.gui then
return wezterm.gui.get_appearance()
end
return 'Dark'
end
function scheme_for_appearance(appearance)
if appearance:find 'Dark' then
return 'Google Dark (Gogh)'
else
return 'Google Light (base16)'
end
end
config.color_scheme = scheme_for_appearance(get_appearance())
#+end_src
***** Set WebGPU as frontend
Additionally, we also provide enable the WebGpu front-end to solve a font [[https://www.reddit.com/r/wezterm/comments/1eze6zt/colored_blocks_instead_of_text/][rendering issue]].
#+begin_src lua :noweb-ref wezterm-config
-- workaround to tackle WezTerm issue
config.front_end = 'WebGpu'
#+end_src
***** COMMENT Configure keys for theme reloading
#+begin_src lua :noweb-ref wezterm-config
-- reload config using the Cmd + Shift + r binding
config.keys = {
{
key = 'r',
mods = 'CMD|SHIFT',
action = wezterm.action.ReloadConfiguration,
},
}
#+end_src
**** Iterm2
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"iterm2"
#+end_src
**** Kitty
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"kitty"
#+end_src
**** COMMENT Warp
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"warp"
#+end_src
**** Ghostty
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"ghostty"
#+end_src
We set up some reasonable defaults such as themes, which can be examined through =ghostty +list-themes= and greedy app quiting behavior after closing the last tab.
#+begin_src nix :noweb-ref home-darwin-home-file
".config/ghostty/config.ghostty".source = config.lib.file.mkOutOfStoreSymlink ./ghostty/config.ghostty;
#+end_src
**** Cmux
https://cmux.com/
#+begin_quote
Native macOS app built on Ghostty. Vertical tabs, notification rings when agents need attention, split panes, and a socket API for automation.
#+end_quote
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"cmux"
#+end_src
Just trying this because Theo won't stop switching tools and I have some spare time to try out some stuff. https://www.youtube.com/watch?v=EUE8N6mqtGg
*** Window Management
**** JankyBorders
[[https://github.com/FelixKratz/JankyBorders][JankyBorders]] draws a colored border around the active window on macOS, making it immediately obvious which window has keyboard focus — particularly useful when long pauses or accidental touch/click events may silently shift focus without visual feedback. It renders borders without the Accessibility API, which makes it faster than alternatives that do. Requires macOS 14+.
#+begin_src nix :noweb-ref homebrew-taps :noweb yes
"FelixKratz/formulae"
#+end_src
nix-darwin can manage the borders service via launchd using the object form of the brew entry. =restart_service = "changed"= restarts borders when the formula is newly installed or upgraded.
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
{
name = "FelixKratz/formulae/borders";
start_service = true;
restart_service = "changed";
}
#+end_src
Symlink the config into the expected XDG path. Using =${dotfilesPath}= to avoid the nix store coercion issue (see Claude section note).
#+begin_src nix :noweb-ref home-darwin-home-file
".config/borders/bordersrc".source = config.lib.file.mkOutOfStoreSymlink "${dotfilesPath}/borders/bordersrc";
#+end_src
The =bordersrc= is a shell script that =borders= reads on startup to configure border appearance. Since nix-darwin manages the service lifecycle, there is no trailing =&= — the service manager handles daemonization.
Active color is the strong pink from [[https://asabina.de][asabina.de]] — =rgb(255, 85, 131)= → =0xffff5583= in JankyBorders' =0xAARRGGBB= format. This color is vivid enough to be legible on both light and dark backgrounds, so a single value works across themes.
#+begin_src bash :tangle borders/bordersrc :tangle-mode (identity #o755) :mkdirp yes :shebang "#!/bin/bash"
# Tangled from README.org — edit there, not here.
# https://github.com/FelixKratz/JankyBorders
borders \
active_color=0xffff5583 \
inactive_color=0xff494d64 \
width=5.0 \
style=round
#+end_src
***** Light/dark theme switching
JankyBorders does not natively watch for macOS appearance changes — it reads =bordersrc= once at startup. Two options for dynamic switching:
****** Option A — single vivid color (current approach, simplest)
The pink =0xffff5583= pops on both dark and light backgrounds. No switching logic needed. If the inactive color looks off in light mode, adjust =inactive_color= to a mid-grey like =0xff9ca0a8=.
****** Option B — theme-aware restart via launchd WatchPaths
Add a launchd agent that watches =~/Library/Preferences/.GlobalPreferences.plist= (where macOS writes =AppleInterfaceStyle= on theme change) and restarts the borders service when it changes.
The =bordersrc= script detects the current theme at runtime:
#+begin_src bash :eval no
# detect dark mode: `defaults read -g AppleInterfaceStyle` returns "Dark" or exits non-zero in light mode
if defaults read -g AppleInterfaceStyle 2>/dev/null | grep -q Dark; then
ACTIVE=0xffff5583 # pink on dark
INACTIVE=0xff494d64
else
ACTIVE=0xffff5583 # same pink reads fine on light too
INACTIVE=0xff9ca0a8 # lighter inactive for light mode
fi
borders active_color=$ACTIVE inactive_color=$INACTIVE width=5.0 style=round
#+end_src
The WatchPaths agent would trigger =brew services restart borders= on plist change. This is more moving parts than Option A warrants unless the inactive color becomes a real issue in light mode.
Stick with Option A for now; revisit if the inactive border is visually distracting in light mode.
*** Networking
Install Wireguard tools https://github.com/WireGuard/wireguard-tools on your MacOS.
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"wireguard-tools"
#+end_src
*** Hex editors/viewers
#+begin_src nix :noweb-ref dev-packages
xxd
hexyl
#+end_src
**** Bat
On NixOS, we install bat through the programs facility:
#+begin_src nix :noweb yes :noweb-ref common-programs
programs.bat = {
enable = true;
config = {
theme = "base16";
};
};
#+end_src
On Darwin, we install it into our home-manager setup:
#+begin_src nix :noweb-ref home-darwin
programs.bat = {
enable = true;
config = {
theme = "base16";
};
};
#+end_src
*** COMMENT Reverse engineering
#+begin_src nix :noweb-ref nix-darwin-packages-intel
ghidra-bin
#+end_src
*** Diagramming
**** Kap
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"kap"
#+end_src
**** Shottr
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"shottr"
#+end_src
**** Drawio
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"drawio"
#+end_src
**** Figma
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"figma"
#+end_src
**** Open Design
[[https://formulae.brew.sh/cask/open-design][Open Design]] is an open-source design tool.
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"open-design"
#+end_src
**** Framer
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"framer"
#+end_src
**** Paper
[[https://paper.design/][Paper]] is a web-based "connected canvas" design tool for building interfaces and prototypes on web standards (HTML/CSS), with real-time design↔code sync and AI-agent/MCP integration. Installed via the [[https://formulae.brew.sh/cask/paper-design][=paper-design= cask]] (arm64, macOS >= 12).
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"paper-design"
#+end_src
**** Rive
[[https://rive.app][Rive]], like Lottie provides tooling to animate assets for mobile apps but unlike Lottie owns the E2E stack where Lottie requires the use of multiple disconnected tools in order to author Lottie animations. Rive furthermore boasts support for state-aware animations.
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"rive"
#+end_src
**** Graphviz
#+begin_src nix :noweb-ref nix-packages-darwin-common
graphviz
#+end_src
*** Shell
**** Linters for shell scripts
#+begin_src nix :noweb-ref dev-packages
shellcheck
shfmt
#+end_src
**** Zoxide
The [[https://github.com/ajeetdsouza/zoxide][zoxide]] CLI tool is smarter alternative to =cd= which allows us to enter directories quickly by using partial phrases, like running =z dot= instead of =cd ~/Code/vidbina/dotfiles=, if that entry is in the shell's history to be matched against the phrase =dot=.
#+begin_src nix :noweb yes :noweb-ref home-darwin-programs
zoxide.enable = true;
#+end_src
**** Fzf
The [[https://github.com/junegunn/fzf][fzf]] CLI and TUI tool and library that is a popular fuzzy finder and used under the hood of a lot of other tools. Use it as a filter to find matches through
#+begin_src bash
echo $SOMETHING | fzf --filter="something"
#+end_src
or use the interactive picker by not specifying a filter.
#+begin_src nix :noweb yes :noweb-ref home-darwin-programs
fzf.enable = true;
#+end_src
**** Asciinema
:PROPERTIES:
:CUSTOM_ID: asciinema
:END:
#+begin_src nix :noweb-ref dev-packages
asciinema
#+end_src
***** TODO Symlink config for Asciinema
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/asciinema ${HOME}/.config/asciinema
#+end_src
*** Study
**** Exercism
#+begin_src nix :noweb-ref dev-packages
pkgs.exercism
#+end_src
*** HTML, Web
#+begin_src nix :noweb-ref dev-packages
pkgs.html-tidy
#+end_src
**** COMMENT Inspector
#+begin_src nix :noweb-ref dev-packages
pkgs.wuzz # cURL-like TUI HTTP request inspection tool
#+end_src
**** Web Servers
#+begin_src nix :noweb-ref dev-packages
pkgs.httpie
pkgs.httplab
#+end_src
*** DONE GCC
- State "TODO" from [2023-10-03 Tue 18:17] \\
Verify that glibc is not available for Darwin and merge the separated configs or provide explanation.
#+begin_src nix :noweb-ref dev-packages
pkgs.checkmake
#pkgs.cmakeCurses
pkgs.gnumake
#+end_src
For now, isolate the Linux-specific dev packages from the more general dev packages but we *should be able to install glibc on macOS*.
#+begin_src nix :noweb-ref dev-packages-linux
pkgs.glibc
pkgs.gdb
#+end_src
*** COMMENT Haskell
#+begin_src nix :noweb-ref dev-packages
pkgs.ghc
pkgs.ghcid
#+end_src
*** Gleam
#+begin_src nix :noweb-ref dev-packages
pkgs.gleam
#+end_src
*** LSP
**** Nixd Language Server
Since I use Nix quite heavily to almost all my configuration management problems, it helps to have a Nix Language Server globally installed.
Installing nixd because Zed was looking for it on <2024-12-21 Sat>.
#+begin_src nix :noweb-ref dev-packages
pkgs.nixd
#+end_src
We also install nixfmt since I noticed some =formatting nixfmt command exited with 65280= errors when navigating nix code in Zed.
#+begin_src nix :noweb-ref dev-packages
pkgs.nixfmt
#+end_src
**** Typescript Language Server
#+begin_src nix :noweb-ref dev-packages
pkgs.typescript-language-server
#+end_src
*** Tree-sitter
#+begin_src nix :noweb-ref dev-packages
pkgs.tree-sitter
#+end_src
*** DSL
**** jq, yq, jless
#+begin_src nix :noweb-ref dev-packages
pkgs.jq
pkgs.yq
pkgs.jless
#+end_src
*** Document tools
**** Poppler
[[https://poppler.freedesktop.org/][Poppler]] is a PDF rendering library that ships a suite of CLI utilities: =pdftotext=, =pdftoppm=, =pdfinfo=, =pdfimages=, =pdfseparate=, =pdfunite=, etc.
#+begin_src nix :noweb-ref dev-packages
pkgs.poppler-utils
#+end_src
*** DB
**** SQLite
#+begin_src nix :noweb-ref dev-packages
pkgs.sqlite-interactive
#+end_src
**** Redis
#+begin_src nix :noweb-ref dev-packages
pkgs.redis
#+end_src
*** File system
**** fswatch
[[https://github.com/emcrisostomo/fswatch][fswatch]] is a cross-platform file change monitor using native OS APIs (FSEvents on macOS, inotify on Linux). Useful for triggering rebuilds or redraws on file changes.
#+begin_src nix :noweb-ref dev-packages
pkgs.fswatch
#+end_src
*** Linux Hacking
I have issues with my touchpad often enough and also have issues with Chromium hanging here and there. It's time that I learned to dig into some of the Linux innards and do some good kernel watching.
**** pidof
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"pidof"
#+end_src
**** Linux-like Hardware Tinkering on MacOS
Instead of installing lsusb directly on MacOS, we install [[http://www.linux-usb.org/][usbutils]] ([[https://github.com/gregkh/usbutils][GitHub]]) which should contain the =lsusb= and =usbhid-dump= CLI tools.
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"usbutils"
#+end_src
**** Linux Input Debugging/Kernel Watching
See https://lwn.net/Articles/658948/
***** COMMENT Linsk
In order to mount Linux partitions like ext4 under MacOS, we may want to use [[https://github.com/AlexSSD7/linsk][Linsk]].
#+begin_src nix :noweb-ref nix-darwin-packages-common
inputs.linsk.packages.${stdenv.hostPlatform.system}.default
#+end_src
***** COMMENT libinput
https://wayland.freedesktop.org/libinput/doc/latest/index.html
#+begin_src nix :noweb-ref dev-packages
pkgs.libinput
#+end_src
***** xinput
1. List xinputs
#+begin_src bash
xinput --list
#+end_src
2. Show properties for device
#+begin_src bash
xinput show-props ID
#+end_src
***** evemu
https://www.freedesktop.org/wiki/Evemu/
https://wiki.ubuntu.com/Multitouch/Testing/Evemu
#+begin_src nix :noweb-ref dev-packages-linux
pkgs.evemu
#+end_src
- evemu-describe
- evemu-device
- evemu-event
- evemu-play
- evemu-record
#+begin_src bash
evemu-record /dev/input/event13 touchpad-debug.evemu
#+end_src
***** TODO Debug laggy/choppy touchpad
Recorded some data while I was observing the choppy behavior
#+begin_src bash
evemu-record /dev/input/event13 touchpad-debug.evemu
#+end_src
Then replayed the recording to confirm choppiness in the recorded output
#+begin_src bash
evemu-play touchpad-debug.evemu
#+end_src
According to ChatGPT:
#+begin_quote org
[!TIP]
If the recording from evemu-record is already choppy, the problem is likely at a lower level than libinput. Libinput processes the events given by the kernel, so if the kernel events are choppy, libinput will also see choppy data.
Here are some steps you can take to debug the issue:
- Check the Kernel Version: As mentioned before, the issue may lie within the kernel. If you're using an old version of the kernel, consider updating it.
- Check for Hardware Issues: If possible, test the trackpad in a different operating system (like Windows or a different Linux distribution) to rule out hardware issues.
- Check for Dropped Events: The evemu-record tool records events as they come from the kernel. If events are being dropped, that might cause choppy input. Use the evtest tool to check if any events are being dropped.
- Check for Firmware Issues: It might be possible that your laptop's firmware is causing issues. Check the manufacturer's website for any firmware updates.
- Check dmesg for Errors: Run dmesg | grep -i error to check for any hardware errors related to the touchpad.
- Contact the libinput Community: If you're unable to resolve the issue yourself, consider reaching out to the libinput community for help. They might be able to provide more specific guidance.
- Remember, always be careful when upgrading the kernel or firmware, or changing system settings. Always backup your data before making significant changes to your system.
#+end_quote
Reading https://www.dell.com/support/kbdoc/de-de/000150104/precision-xps-allgemeine-problemloesung-f-uuml-er-touchpad-maus-in-ubuntu and concluding that dmesg needs to be monitored for kernel events
#+begin_src bash
dmesg -H --follow
#+end_src
#+begin_src text
[May24 10:26] systemd-gpt-auto-generator[83303]: EFI loader partition unknown, exiting.
[ +0.000006] systemd-gpt-auto-generator[83303]: (The boot loader did not set EFI variable LoaderDevicePartUUID.)
[May24 11:04] input: DLL0945:00 04F3:311C Touchpad as /devices/virtual/input/input70
[May24 11:07] input: DLL0945:00 04F3:311C Touchpad as /devices/virtual/input/input71
#+end_src
Is the touchpad being reconnected over different ports?
#+begin_src text
> xinput --list
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ ELAN2D24:00 04F3:2D24 id=11 [slave pointer (2)]
⎜ ↳ DLL0945:00 04F3:311C Mouse id=12 [slave pointer (2)]
⎜ ↳ PS/2 Generic Mouse id=18 [slave pointer (2)]
⎜ ↳ DLL0945:00 04F3:311C Touchpad id=13 [slave pointer (2)]
⎣ Virtual core keyboard id=3 [master keyboard (2)]
↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
↳ Video Bus id=6 [slave keyboard (3)]
↳ Video Bus id=7 [slave keyboard (3)]
↳ Power Button id=8 [slave keyboard (3)]
↳ Integrated_Webcam_HD: Integrate id=9 [slave keyboard (3)]
↳ Integrated_Webcam_HD: Integrate id=10 [slave keyboard (3)]
↳ Intel HID events id=14 [slave keyboard (3)]
↳ Intel HID 5 button array id=15 [slave keyboard (3)]
↳ Dell WMI hotkeys id=16 [slave keyboard (3)]
↳ AT Translated Set 2 keyboard id=17 [slave keyboard (3)]
#+end_src
Searching for DLL0945:00 04F3:311C on Google yields https://www.dell.com/community/XPS/XPS-15-9510-Touchpad-Intermittent-touchpad-lag/td-p/8012567/page/4 where the following comment is posted:
#+begin_quote
[!NOTE]
I can also reproduce that this is related to the palm rejection on the side of the touchpad. Usually the cursor does not move when I move the finger on the very right side of the touchpad. Every time the cursor is laggy, the palm rejection does not work and I can move the cursor by touching the pad on the very right side.
I also tried out the mtouch drivers instead of libinput but the problem persists. so I suppose that the problem is related to the firmware of the touchpad.
#+end_quote
***** CANCELED mtdiag-qt
https://github.com/bentiss/mtdiag-qt
***** CANCELED mtview
https://github.com/whot/mtview
***** COMMENT mtr
https://github.com/traviscross/mtr
#+begin_src nix :noweb-ref dev-packages
pkgs.mtr
#+end_src
*** Virtualization
**** Docker
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"docker-desktop"
#+end_src
**** UTM
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"utm"
#+end_src
*** Calculators
**** pcalc
The [[https://github.com/alt-romes/programmer-calculator][pcalc]] util can come in handy when one needs to conduct conversions between bases (Like octal to binary, hex to binary, etc) and calculate operations (ADD, MOD, XOR, etc.) between different operands. I initially set out to install the PCalc calculation util https://pcalc.com/ to calculate logs and work with other advanced math functions, but somehow I hit a name collision here and ended up realising that the other pcalc may be useful to me too... someday, so, we're keeping it.
For MacOS, we just install pcalc using the brew:
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"pcalc"
#+end_src
**** duti
The [[https://github.com/moretension/duti/][duti]] utility allows us to set default applications for document types and URL schemes on macOS from the CLI. We use it in a nix-darwin activation script to declaratively enforce app handlers on every =darwin-rebuild switch=.
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"duti"
#+end_src
*** Syncthing
Navigate to [[http://localhost:8384/][Syncthing portal]] to configure your setup. As per [2022-05-05 Thu 12:08], the syncthing service in home-manager is only declarative to the extend of turning it on and providing extra CLI options to start the service with.
Consult the [[https://docs.syncthing.net/intro/getting-started.html][Getting Started]] guide to learn how to set it up "imperatively" (i.e.: setting up peers and generating their IDs and copying the needed information over to the other syncthing peers to establish connections) through the portal.
**** Syncthing Daemon on Darwin
#+begin_src nix :noweb-ref home-darwin
services.syncthing = {
enable = true;
};
#+end_src
***** DONE Issue: Syncthing not automatically started on macOS
:LOGBOOK:
- State "DONE" from "TODO" [2024-12-23 Mon 10:28] \\
Checking on <2024-12-21 Sat>, I noticed that syncthings is running on tokyo23 (ARM) so we're good here.
:END:
[2024-02-07 Wed] On macOS, the syncthing service isn't running which was confirmed by running:
#+begin_src bash
launchctl list org.nix-community.home.syncthing
#+end_src
where the output is
#+begin_src text
{
"LimitLoadToSessionType" = "Aqua";
"Label" = "org.nix-community.home.syncthing";
"OnDemand" = true;
"LastExitStatus" = 19968;
"Program" = "/nix/store/rnigg5xf6n2jxda3ivscrn0yzw474dq4-syncthing-1.26.1/bin/syncthing";
"ProgramArguments" = (
"/nix/store/rnigg5xf6n2jxda3ivscrn0yzw474dq4-syncthing-1.26.1/bin/syncthing";
"-no-browser";
"-no-restart";
"-logflags=0";
);
};
#+end_src
which seems at odds with the nix definition for syncthing
#+begin_src nix
launchd.agents.syncthing = {
enable = true;
config = {
ProgramArguments = syncthingArgs;
KeepAlive = {
Crashed = true;
SuccessfulExit = false;
};
ProcessType = "Background";
};
};
#+end_src
as =KeepAlive= is defined in the nix config, but missing in the observed launch output, furthermore =OnDemand= isn't mentioned at all in the nix config. 🤷🏿
#+begin_quote
[!NOTE]
It seems that the [[https://github.com/nix-community/home-manager/blob/f99eace7c167b8a6a0871849493b1c613d0f1b80/modules/launchd/launchd.nix#L167][OnDemand]] option is a pre macOS 10.5 key which has been superceded by KeepAlive.
#+end_quote
Just to confirm, Syncthing really isn't running, I have checked the process list for a corresponding entry:
#+begin_src bash
ps aux | grep syncthing
#+end_src
Trying to start syncthing through
#+begin_src bash
launchctl start org.nix-community.home.syncthing
#+end_src
yields status 134 (SIGABRT) and 139 (SIGSEGV). Retrying with =sudo= fails with status 3.
Attempts to kickstart with
#+begin_src bash
launchctl kickstart gui/501/org.nix-community.home.syncthing
#+end_src
also fail with =139: Service cannot presently execute= but of course I don't have any freaking logs.
#+begin_quote
😕 I just ran the =launchctl list= and =ps= commands on my personal MacBook and found that syncthing is running as a daemon there. Perhaps I need a system restart. I recall that starting/stopping logic with launchd is quite different in terms of UX to systemd and likely the start/stop commands just don't do the same thing.
#+end_quote
As a fallback, just start =syncthing= through a terminal with the temporary added benefit of having a log/trace of Syncthing's actions. This needs further exploration.
A deeper dive, leads me through https://www.launchd.info/ which outlines where the different files for job definitions are stored. For me ~/Library/LaunchAgents/org.nix-community.home.syncthing.plist seems to match the definition in the home-manager codebase, unlike the output I was seeing from =launchctl list= earlier.
#+begin_src xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<dict>
<key>Crashed</key>
<true/>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>Label</key>
<string>org.nix-community.home.syncthing</string>
<key>ProcessType</key>
<string>Background</string>
<key>ProgramArguments</key>
<array>
<string>/nix/store/rnigg5xf6n2jxda3ivscrn0yzw474dq4-syncthing-1.26.1/bin/syncthing</string>
<string>-no-browser</string>
<string>-no-restart</string>
<string>-logflags=0</string>
</array>
</dict>
</plist>
#+end_src
Perhaps the new job definition has simply not been loaded, which would be a failing of the =darwin-rebuild switch= run we did earlier. So, for next time, I should remember to try the following:
#+begin_src bash
sudo launchctl load ~/Library/LaunchAgents/org.nix-community.home.syncthing.plist
sudo launchctl enable gui/501/org.nix-community.home.syncthing
#+end_src
but for now, I just try a restart and see what happens. 🤞🏿
**** COMMENT Syncthing Service on Linux
#+begin_src nix :noweb-ref home-linux-services
services.syncthing = {
enable = true;
tray = { enable = true; };
};
#+end_src
**** TODO Set ignore file for Syncthing or move some sensitive stuff out of synced folders
Especially for things link mail indices and Org-roam databases, I may need to do this.
- https://docs.syncthing.net/users/ignoring.html
- https://github.com/org-roam/org-roam/issues/977
- https://github.com/org-roam/org-roam/issues/550
** COMMENT E-mail
We configure file:mail.nix as our mail-related config file.
#+begin_src nix :noweb-ref common-imports
./mail.nix
#+end_src
I have multiple ways of handling e-mails. For starters, I process nearly all of my e-mails that require deep thought and the ability to verify extraneous sources from the comfort of a workstation (i.e.: my laptop and trusted 2nd brain). Mobile is only used for the quick things on the go and I don't need much fancy capabilities there since I want to see these messages again once I'm behind the workstation just to verify that I didn't miss anything during the daze of being on the go (which tends to be the case when I'm on mobile).
I have used neomutt in combination with Neovim and mu4e in Emacs for nearly half a year, I've recently started experimenting with notmuch inside of Emacs which is another tool that is built on top of mu indexer capabilities.
#+begin_src nix :noweb yes :tangle mail.nix
# Tangled from README.org
{ config, pkgs, ... }:
{
home.packages = with pkgs; [
<<mail-packages>>
];
}
#+end_src
*** Packages for Mutt-like Mail
The following packages were part of my config before and are just seperated to help me break this down into subordinate chapters:
#+begin_src nix :noweb-ref mail-packages
isync
mb2md
neomutt
urlview
#+end_src
**** COMMENT offlineimap
#+begin_src nix :noweb-ref mail-packages
offlineimap
#+end_src
**** msmtp
#+begin_src nix :noweb-ref mail-packages
msmtp
#+end_src
**** Notmuch
Much of my work-related comms transpires over e-mail. In order to obtain [[https://tongfamily.com/2022/01/22/superhuman-hidden-commands-to-top-and-bottom-are-gg-and-g/][superhuman-level-like-or-better]] 🙊 convenience, I am using [[https://notmuchmail.org/][notmuch]] which has [[https://notmuchmail.org/frontends/][plenty of frontends]] available.
#+begin_src nix :noweb-ref mail-packages
notmuch
notmuch-mutt
#+end_src
*** DONE Workers
See my private dotfiles where I have defined a mbsync service to handle synchronization of mail. Indexing could be handled through as a =PostExec= hook in the mail retrieval service but this will cause problems with mu4e spinning up mu/server to reindex the maildir and obtaining the read/write lock on the Xapian store.
*** COMMENT Issues
#+begin_src text
sendmail: authentication failed (method PLAIN)
sendmail: server message: 454 4.7.0 Temporary authentication failure:
sendmail: could not send mail (account work-asabina-gmbh from /home/vidbina/.config/msmtp/config)
#+end_src
** Neovim
For Neovim, remember that CoC completions basically work through use of the =C-n= and =C-p= binding to cycle through next and previous items in the completion listing.
*** vim-configuration for Neovim
#+begin_quote
[!WARNING]
⚠️ I haven't relied on init.nvim for a while since I broke my configuration a little while ago in my attempts to pull vim-plug with Nix and then manage all my other plugins through the init.nvim file. As a lazyperson's way out, I have simply given up and started managing my entire nvim configuration in nix.
[2024-02-19 Mon]: Tangling init.vim from the same snippets that I use in nix. Only difference is that init.vim contains the packages that are being installed through Pathogen, while the nix config handles package management for vim itself.
#+end_quote
In case you need to use the Neovim configuration manually, please symlink the generated file into your home directory by running the following (or some derivative thereof that is applicable to your environment):
#+begin_src shell
ln -s ${PATH_TO_DOTFILE}/nvim ${HOME}/.config/nvim
#+end_src
Our configuration, basically does the following:
- set tabbing behavior (expand tabs to 2 spaces)
#+begin_src vimrc :noweb-ref neovim-config
set tabstop=2 " tab stop to 2 spaces
set shiftwidth=2 " shift width by 2 spaces
set expandtab " expand tabs to spaces
#+end_src
- enable mouse in all modes
#+begin_src vimrc :noweb-ref neovim-config
set mouse=a
set number
":map <ScrollWheelUp> <C-Y>
":map <ScrollWheelDown> <C-E>
#+end_src
- Set remaining vim settings, like terminal colors (useful for CLI mode, markdown settings that I'm not even sure are still useful or relevant today and some other misc settings.
#+begin_src vimrc :noweb-ref neovim-config
colorscheme dim
" https://vi.stackexchange.com/a/45130
set notermguicolors
set t_Co=16
let g:vim_markdown_frontmatter = 1
let g:vim_markdown_math = 1
let g:vim_markdown_fenced_languages = ['nix=nix', 'Dockerfile=dockerfile']
let g:vim_markdown_new_list_item_indent = 2
let g:vim_markdown_auto_insert_bullets = 0
set wrap
set ignorecase
set nofoldenable
set nofixeol
#+end_src
- define Plug extensions, which are only relevant for the manual configuration scenario and not when you are using Nix to manage *vim
#+begin_src vimrc :noweb-ref neovim-plugged
call plug#begin("~/.local/share/nvim/plugged")
Plug 'airblade/vim-gitgutter'
Plug 'aklt/plantuml-syntax'
Plug 'dense-analysis/ale'
Plug 'derekwyatt/vim-scala'
Plug 'ElmCast/elm-vim'
Plug 'godlygeek/tabular'
Plug 'hashicorp/sentinel.vim'
Plug 'hashivim/vim-terraform'
"Plug 'https://github.com/hrother/offlineimaprc.vim.git'
Plug 'https://github.com/junegunn/goyo.vim.git'
Plug 'https://github.com/plasticboy/vim-markdown.git'
Plug 'isRuslan/vim-es6'
Plug 'jparise/vim-graphql'
Plug 'leafgarland/typescript-vim', { 'for': 'typescript' }
Plug 'LnL7/vim-nix'
Plug 'majutsushi/tagbar'
"https://github.com/neoclide/coc.nvim
"Load VSCode extensions and host language servers
"Plug 'neoclide/coc.nvim', { 'branch': 'release' }
Plug 'preservim/nerdtree'
Plug 'prettier/vim-prettier'
Plug 'purescript-contrib/purescript-vim'
Plug 'saltstack/salt-vim'
"Plug 'sbdchd/neoformat'
Plug 'sigmike/vim-taskjuggler'
Plug 'tomlion/vim-solidity'
Plug 'tpope/vim-fugitive'
Plug 'vim-airline/vim-airline'
Plug 'vim-scripts/openvpn'
Plug 'wannesm/wmgraphviz.vim'
Plug 'jeffkreeftmeijer/vim-dim', { 'branch': 'main' }
call plug#end()
#+end_src
We compose the different settings into init.vim and tangle the non-Pathogen-related stuff into our nix config (where we define vim packages through nix and therefore won't need Pathogen).
#+begin_src vimrc :noweb yes :tangle nvim/init.vim
" Tangled from README.org
<<neovim-plugged>>
<<neovim-config>>
#+end_src
*** Nix config for Neovim
#+begin_src nix :noweb-ref common-imports
./vim.nix
#+end_src
https://developpaper.com/complete-guide-to-getting-started-with-coc-nvim/
#+begin_src nix :noweb yes :tangle vim.nix
# Tangled from README.org
{ config, pkgs, ... }:
{
home.sessionVariables.EDITOR = "nvim";
programs.neovim = {
enable = true;
plugins = with pkgs.vimPlugins; [
<<nvim-packages>>
];
vimdiffAlias = true;
withPython3 = false; # disable Python bundled into nvim
withRuby = true;
extraConfig = ''
<<neovim-config>>
'';
initLua = ''
-- Tangled from README.org
<<neovim-lua-config>>
'';
};
}
#+end_src
*** Misc Neovim packages installed through Nix
#+begin_src nix :noweb-ref nvim-packages
# deoplete-notmuch
goyo-vim
neoformat
nerdtree
tabular
tagbar
vim-airline
vim-dim
vim-fugitive
vim-gitgutter
#+end_src
**** COMMENT Nvim Language Plugins
#+begin_src nix :noweb-ref nvim-packages
elm-vim
orgmode
plantuml-syntax
typescript-vim
vim-graphql
vim-markdown
vim-nix
vim-prettier
vim-solidity
vim-terraform
wmgraphviz-vim
#+end_src
***** TODO Separate out Nvim language plugins into the respective language configuration section
We should define Nvim language plugins in the section where we install language related tooling, like language servers, etc.
*** COMMENT Neovim LSP Config
Install the [[https://github.com/neovim/nvim-lspconfig][nvim-lspconfig]] package for the LSP client configurations for various languages:
#+begin_src nix :noweb-ref nvim-packages
nvim-lspconfig
#+end_src
Configure lspconfig for the languages we have an interest in:
#+begin_src lua :noweb-ref neovim-lua-config
require'lspconfig'.gleam.setup{}
#+end_src
We map backslack + i (for info) to float the diagnostics window:
#+begin_src lua :noweb-ref neovim-lua-config
-- Float diagnostics window through custom mapping
vim.keymap.set('n', '<Leader>i', function() vim.diagnostic.open_float(nil, {focus=false, scope='cursor'}) end)
#+end_src
See =:h mapleader= for info on the leader key which is set to backslack (=\=) by default. When different, try to run =:echo mapleader= from inside of vim to find out.
*** COMMENT Neovim Treesitter
Removing on <2026-03-14 Sat> becuause of =module 'nvim-treesitter.configs' not found= error.
#+begin_src nix :noweb-ref nvim-packages
nvim-treesitter.withAllGrammars
#+end_src
See https://github.com/nvim-treesitter/nvim-treesitter?tab=readme-ov-file#highlight
#+begin_src lua :noweb-ref neovim-lua-config
require'nvim-treesitter.configs'.setup{
highlight = {
enable = true,
-- Setting this to true will run `:h syntax` and tree-sitter at the same time.
-- Set this to `true` if you depend on 'syntax' being enabled (like for indentation).
-- Using this option may slow down your editor, and you may see some duplicate highlights.
-- Instead of true it can also be a list of languages
additional_vim_regex_highlighting = false,
},
}
#+end_src
*** Make Neovim default editor
** Emacs
We import Emacs into our file:configuration-darwin.nix from our emacs subdirectory:
#+begin_src nix :noweb-ref nix-darwin-imports
./emacs/nix-darwin.nix
#+end_src
and we import the home-manager related part of our config from
#+begin_src nix :noweb-ref home-darwin-imports
./emacs/hm.nix
#+end_src
*** Link .emacs.d from dotfiles into home directory
#+begin_src nix :noweb-ref home-darwin-home-file
".emacs.d".source = config.lib.file.mkOutOfStoreSymlink "${dotfilesPath}/emacs";
#+end_src
*** TODO Tangle nix import of emacs/*.nix
At the moment we import our nix configs for Emacs into our configuration-darwin.nix file and for Linux we haven't really considered how to do this since we don't actively use Linux atm. We'll have to fix this at some point.
** TODO Bring in XMonad configuration
For now, I symlink ~/.xmonad to ~/src/vidbina/xmonad-config and run =xmonad --recompile= to produce the Xmonad binary.
** Window Management, Bars and Launchers
*** COMMENT TODO Bring in xmobar configuration
For now, I symlinked ~/.config/xmobar to ~/src/vidbina/xmobar-configuration.
#+begin_src nix :noweb-ref x-programs
programs.xmobar = {
enable = true;
# extraConfig =
};
#+end_src
*** COMMENT polybar
#+begin_src nix
# TODO: https://gvolpe.com/blog/xmonad-polybar-nixos/
# try polybar sometime
services.taffybar = {
enable = true;
};
#+end_src
*** Hidden Bar
On MacOS, we use [[https://github.com/dwarvesf/hidden/][hidden Bar]] to work around the issue that MacOS doesn't natively provide mechanisms for seeing the menubar items that are hidden when the icon count gets too large or when the focused application menu entries are too many (like with Emacs which has menu entries crossing the camera notch).
#+begin_src nix :noweb-ref homebrew-masapps :noweb yes
"Hidden Bar" = 1452453066;
#+end_src
*** Raycast
We use [[https://www.raycast.com/][Raycast]] as our default Launcher and set it up to replace Spotlight, following the instructions on https://manual.raycast.com/hotkey which are tricky to enforce declaratively in a clean manner.
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"raycast"
#+end_src
I've transfered my Raycast settings through the *Export settings & data* option which produces a .rayconfig file which I import on another machine. This is a pretty simple way to manage synchronization of Raycast configuration since this doesn't change too often.
**** Window Tiling
Raycast includes a built-in window tiling manager (Settings → Window Management). No declarative path has been found yet — the relevant =com.raycast.macos= preference keys are not publicly documented, so this must be configured manually.
Manual setup:
1. Open Raycast Settings → Window Management
2. Set *Gap* to *Small* (8 pt gaps work well; Tiny causes bottom-screen trimming when [[*JankyBorders][JankyBorders]] borders are active, because the border overlay adds ~5 px that Raycast's geometry doesn't account for)
*** COMMENT Nightlight
Replaced by macOS native Night Shift (System Settings > Displays > Night Shift).
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"smudge/smudge/nightlight"
#+end_src
*** Al Dente
The [[https://apphousekitchen.com/][Al Dente]] app helps us to avoid overcharging our MacBook battery. Since I got a new battery in my MacBook Pro (2018, Intel), this is becoming a useful adddition. Apple Silicon machines apparently have /Optimized Battery Charging/ so we're only installing this for Intel-based Apple devices.
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
(if pkgs.stdenv.hostPlatform.system == "x86_64-darwin" then "aldente" else null)
#+end_src
*** Hammerspoon
I use [[https://www.hammerspoon.org/][Hammerspoon]] for some OSX-specific automations which can be scripted through Lua. Like mapping keybindings to open specific locations in Finder, opening specific apps within a workstation or rendering notification or alerts with some useful information and more.
We link the hammerspoon directory into our homedir in order to set up the necessary Spoons and the init.lua:
#+begin_src nix :noweb-ref home-darwin-home-file
".hammerspoon".source = config.lib.file.mkOutOfStoreSymlink ./hammerspoon;
#+end_src
We load the Spoons and define our own bindings and more in the init.lua file that we symlinked into our homedir previously. Each capability is its own noweb ref — =COMMENT= a heading to disable it without deleting code. See [[https://zzamboni.org/post/my-hammerspoon-configuration-with-commentary/][zzamboni's config]] for inspiration.
#+begin_src lua :noweb yes :tangle hammerspoon/init.lua
-- Tangled from README.org
<<hs-core>>
<<hs-mouse-highlight>>
<<hs-caffeine>>
<<hs-ksheet>>
<<hs-hskeybindings>>
<<hs-inspect>>
<<hs-terminal-launcher>>
#+end_src
**** Core
Base binding setup (=⌃⌥⌘=), cheatsheet variable, help (=⌃⌥⌘ H=) and [[https://www.hammerspoon.org/go/#simple-configuration-reloading][config reload]] (=⌃⌥⌘ R=).
#+begin_src lua :noweb-ref hs-core
hsBaseBinding = {"alt", "cmd", "ctrl"}
strBaseBinding = "⌃⌥⌘"
cheatsheet = "💡"
-- A dummy binding for Hammerspoon
hs.hotkey.bind(
hsBaseBinding,
"H",
function()
hs.alert.show(cheatsheet)
hs.notify.new({title="Hammerspoon", informativeText=cheatsheet}):send()
end
)
cheatsheet = cheatsheet .. "\n" .. strBaseBinding .. " H = help"
-- https://www.hammerspoon.org/go/#simple-configuration-reloading
hs.hotkey.bind(
hsBaseBinding,
"R",
function()
hs.alert.show("Reloading Hammerspoon config")
hs.reload()
end
)
cheatsheet = cheatsheet .."\n" .. strBaseBinding .. " R = reload"
#+end_src
**** Mouse highlight
[[https://www.hammerspoon.org/go/#drawing-on-the-screen][Draw a red circle]] around the cursor for 1 second (=⌃⌥⌘ D=).
#+begin_src lua :noweb-ref hs-mouse-highlight
-- https://www.hammerspoon.org/go/#drawing-on-the-screen
mouseCircle = nil
mouseCircleTimer = nil
function mouseHighlight()
-- Delete an existing highlight if it exists
if mouseCircle then
mouseCircle:delete()
if mouseCircleTimer then
mouseCircleTimer:stop()
end
end
-- Get the current co-ordinates of the mouse pointer
mousepoint = hs.mouse.absolutePosition()
-- Prepare a big red circle around the mouse pointer
mouseCircle = hs.drawing.circle(hs.geometry.rect(mousepoint.x-40, mousepoint.y-40, 80, 80))
mouseCircle:setStrokeColor({["red"]=1,["blue"]=0,["green"]=0,["alpha"]=1})
mouseCircle:setFill(false)
mouseCircle:setStrokeWidth(5)
mouseCircle:show()
-- Set a timer to delete the circle after 3 seconds
mouseCircleTimer = hs.timer.doAfter(
1,
function()
mouseCircle:delete()
mouseCircle = nil
end
)
end
hs.hotkey.bind(hsBaseBinding, "D", mouseHighlight)
cheatsheet = cheatsheet .. "\n" .. strBaseBinding .. " D = mouse highlight"
#+end_src
**** COMMENT Caffeine
Toggle sleep prevention via the [[https://www.hammerspoon.org/Spoons/Caffeine.html][Caffeine Spoon]] (=⌃⌥⌘ Z=). Disabled — redundant with Amphetamine.
#+begin_src lua :noweb-ref hs-caffeine
hs.loadSpoon("Caffeine")
isCaffeinated = false
hs.hotkey.bind(
hsBaseBinding,
"Z",
function()
if not isCaffeinated then
hs.alert.show("Buzzed! Flattie mode! ☕")
spoon.Caffeine:start()
else
hs.alert.show("Letting that buzz wear off. 🥱")
spoon.Caffeine:stop()
end
isCaffeinated = not isCaffeinated
end
)
cheatsheet = cheatsheet .. "\n" .. strBaseBinding .. " Z = ☕"
#+end_src
**** COMMENT KSheet
Show current app's shortcuts via the [[https://www.hammerspoon.org/Spoons/KSheet.html][KSheet Spoon]] (=⌃⌥⌘ K=). Disabled — Raycast covers this.
#+begin_src lua :noweb-ref hs-ksheet
hs.loadSpoon("KSheet")
spoon.KSheet:bindHotkeys(
{
toggle = {hsBaseBinding, "K"}
}
)
cheatsheet = cheatsheet .. "\n" .. strBaseBinding .. " K = KSheet"
#+end_src
**** COMMENT HSKeybindings
List Hammerspoon's own hotkeys via the [[https://www.hammerspoon.org/Spoons/HSKeybindings.html][HSKeybindings Spoon]] (=⌃⌥⌘ /=). Disabled — mostly useful for debugging HS itself.
#+begin_src lua :noweb-ref hs-hskeybindings
hs.loadSpoon("HSKeybindings")
isShowingHSKeybindings = false
hs.hotkey.bind(
hsBaseBinding,
"/",
function()
if not isShowingHSKeybindings then
hs.alert.show("Showing HSKeybindings")
spoon.HSKeybindings:show()
else
hs.alert.show("Hiding HSKeybindings")
spoon.HSKeybindings:hide()
end
isShowingHSKeybindings = not isShowingHSKeybindings
end
)
cheatsheet = cheatsheet .. "\n" .. strBaseBinding .. " K = HSKeybindings"
#+end_src
**** COMMENT Inspect
Show caffeinate state (=⌃⌥⌘ .=). Disabled — only useful alongside the Caffeine spoon.
#+begin_src lua :noweb-ref hs-inspect
hs.hotkey.bind(
hsBaseBinding,
".",
function()
hs.alert.show("Inspecting Hammerspoon")
hs.alert.show("displayIdle: " .. (hs.caffeinate.get("displayIdle") and "On" or "Off"))
hs.alert.show("systemIdle: " .. (hs.caffeinate.get("systemIdle") and "On" or "Off"))
hs.alert.show("system: " .. (hs.caffeinate.get("system") and "On" or "Off"))
end
)
#+end_src
**** COMMENT iTerm launcher
Open or create an iTerm window (=⌃⌥⌘ ⏎=). Disabled — switched to Ghostty which has its own keybindings.
#+begin_src lua :noweb-ref hs-terminal-launcher
hs.hotkey.bind(
hsBaseBinding,
"return",
function()
if hs.application.find("iTerm") then
hs.osascript.applescript([[
tell application "iTerm"
create window with default profile
end tell
]])
else
hs.application.open("iTerm")
end
end
)
cheatsheet = cheatsheet .. "\n" .. strBaseBinding .. " ⏎ = iTerm 👨🏿💻"
#+end_src
** Multimedia
#+begin_src nix :noweb yes :tangle multimedia.nix
# Tangled from README.org
{ config, pkgs, lib, options, ... }:
{
home.packages = with pkgs; [
<<multimedia-packages>>
];
}
#+end_src
*** OBS
On MacOS, we just install OBS with homebrew:
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"obs" # for streaming
#+end_src
**** COMMENT On Linux
https://obsproject.com/wiki/install-instructions
#+begin_src nix :noweb-ref multimedia-packages
# For error: ARB_GLX_create_context not supported!
# see the following resources:
# - https://github.com/nix-community/home-manager/issues/1424
obs-studio
#+end_src
***** TODO Figure out OpenGL configuration
We had this binding nixgl into the multimedia.nix block but we are temporariliy ripping this out.
#+begin_src nix
let
# TODO: Find a cleaner implementation, like an pkgs overlay at shell.nix?!?
# Borrowed from Browser config
#nixgl = import <NIXGL> { inherit pkgs; };
in
#+end_src
This bit we were trying to use to trick OBS into finding OpenGL-related paths. Didn't work so I'm shelving it temporarily. Using StreamYard meanwhile.
#+begin_src nix :noweb-ref multimedia-packages
# - https://github.com/guibou/nixGL
#nixgl {}
#+end_src
*** GTK+ UVC Viewer (GUVCView)
https://guvcview.sourceforge.net/
#+begin_src nix :noweb-ref multimedia-packages
guvcview
#+end_src
*** Spotify
As per <2024-11-26 Tue>, I'm moving back to Spotify after many years with TIDAL. Basically dropping TIDAL because I keep getting logged out of their app on my mobile phone and laptop and am just getting annoyed by it. Furthermore, I've had it multiple times that offline content was not available when I was travelling. What am I paying for if it doesn't work at the times I need it most.
#+begin_src nix :noweb-ref homebrew-casks
"spotify"
#+end_src
*** Tidal
#+begin_src nix :noweb-ref homebrew-casks
"tidal"
#+end_src
*** IINA
[[https://iina.io][IINA]] is a lightweight macOS-native media player built on mpv. Selected in [[https://linear.app/asabina/issue/VID-644][VID-644]] as the recommended GUI player for wav and general audio/video file playback.
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"iina"
#+end_src
*** V4l utils
https://linuxtv.org/projects.php
#+begin_src nix :noweb-ref multimedia-packages
v4l-utils
#+end_src
** Gaming
*** Steam
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"steam"
#+end_src
** Browsers
#+begin_src nix :noweb yes :tangle browser.nix
# Tangled from README.org
{ config, pkgs, lib, options, ... }:
let
# TODO: Find a cleaner implementation, like an pkgs overlay at shell.nix?!?
nur = import <NUR> { inherit pkgs; };
sources = import ./nix/sources.nix;
nixpkgs-bleeding-src = sources."nixpkgs-bleeding";
pkgs-bleeding = import nixpkgs-bleeding-src { };
in
{
home.packages = with pkgs; [
<<browser-packages>>
];
<<browser-chromium>>
<<browser-firefox>>
}
#+end_src
*** Chrome
Install Chrome through homebrew:
#+begin_src nix :noweb-ref homebrew-casks
"google-chrome"
#+end_src
**** COMMENT Previous config
We just want to try the unfree Google Chrome, to test whether this works with Twitch:
#+begin_src nix :noweb-ref browser-packages
google-chrome-dev
#+end_src
We pass along the string equivalent of the package name for use by the =allowUnfreePredicate= in order to instruct Nix to play ball with this "unfree" abomination 🙊:
#+begin_src nix :noweb-ref nixpkgs-unfree
"google-chrome-dev"
#+end_src
#+begin_src bash
chromium --disable-gpu-vsync --disable-frame-rate-limit
#+end_src
- chrome://gpu
- chrome://flags/
**** DONE Debug Chrome freeze-ups (possibly accelleration-related)
Output of starting chromium on [2023-03-04 Sat 16:51]
#+begin_src text
libva error: /run/opengl-driver/lib/dri/iHD_drv_video.so has no function __vaDriverInit_1_0
libva error: /run/opengl-driver/lib/dri/i965_drv_video.so has no function __vaDriverInit_1_0
[5045:5178:0304/164722.289526:ERROR:object_proxy.cc(623)] Failed to call method: org.freedesktop.DBus.Properties.Get: object_path= /org/freedesktop/UPower: org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.UPower was not provided by any .service files
[5045:5178:0304/164722.289875:ERROR:object_proxy.cc(623)] Failed to call method: org.freedesktop.UPower.GetDisplayDevice: object_path= /org/freedesktop/UPower: org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.UPower was not provided by any .service files
[5045:5178:0304/164722.290266:ERROR:object_proxy.cc(623)] Failed to call method: org.freedesktop.UPower.EnumerateDevices: object_path= /org/freedesktop/UPower: org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.UPower was not provided by any .service files
pFontconfig error: Cannot load default config file: No such file: (null)
#+end_src
Note that the content of the object file has a different init func:
#+begin_src bash :wrap src text
nm -gD /run/opengl-driver/lib/dri/iHD_drv_video.so | grep __vaDriverInit
#+end_src
#+RESULTS:
#+begin_src text
0000000000391d50 T __vaDriverInit_1_17
#+end_src
Searching through the other files object files in file:/run/opengl-driver/lib/dri, I noticed that a few do list a v1.0 init function.
#+begin_src bash :wrap src text
nm -gD /run/opengl-driver/lib/dri/nvidia_drv_video.so | grep __vaDriverInit
#+end_src
#+RESULTS:
#+begin_src text
000000000000c480 T __vaDriverInit_1_0
#+end_src
So, we need to clean up some of the drivers if Chromium is trying to resolve which init function to calld dynamically.
Also =vainfo= communicates the version to be beyond 1.0, 1.17 to be precise.
Output of chrome://gpu on [2023-02-11 Sat 23:55]
#+begin_src text
Graphics Feature Status
Canvas: Hardware accelerated
Canvas out-of-process rasterization: Disabled
Direct Rendering Display Compositor: Disabled
Compositing: Hardware accelerated
Multiple Raster Threads: Enabled
OpenGL: Enabled
Rasterization: Hardware accelerated
Raw Draw: Disabled
Video Decode: Hardware accelerated
Video Encode: Software only. Hardware acceleration disabled
Vulkan: Disabled
WebGL: Hardware accelerated
WebGL2: Hardware accelerated
WebGPU: Disabled
Driver Bug Workarounds
clear_uniforms_before_first_program_use
count_all_in_varyings_packing
disable_post_sub_buffers_for_onscreen_surfaces
enable_webgl_timer_query_extensions
exit_on_context_lost
rely_on_implicit_sync_for_swap_buffers
disabled_extension_GL_KHR_blend_equation_advanced
disabled_extension_GL_KHR_blend_equation_advanced_coherent
disabled_extension_GL_MESA_framebuffer_flip_y
Problems Detected
WebGPU has been disabled via blocklist or the command line.
Disabled Features: webgpu
Accelerated video encode has been disabled, either via blocklist, about:flags or the command line.
Disabled Features: video_encode
Clear uniforms before first program use on all platforms: 124764, 349137
Applied Workarounds: clear_uniforms_before_first_program_use
Mesa drivers in Linux handle varyings without static use incorrectly: 333885
Applied Workarounds: count_all_in_varyings_packing
Disable partial swaps on Mesa drivers (detected with GL_RENDERER): 339493
Applied Workarounds: disable_post_sub_buffers_for_onscreen_surfaces
Disable partial swaps on Mesa drivers (detected with GL_VERSION): 339493
Applied Workarounds: disable_post_sub_buffers_for_onscreen_surfaces
Disable KHR_blend_equation_advanced until cc shaders are updated: 661715
Applied Workarounds: disable(GL_KHR_blend_equation_advanced), disable(GL_KHR_blend_equation_advanced_coherent)
Expose WebGL's disjoint_timer_query extensions on platforms with site isolation: 808744, 870491
Applied Workarounds: enable_webgl_timer_query_extensions
Some drivers can't recover after OUT_OF_MEM and context lost: 893177
Applied Workarounds: exit_on_context_lost
Avoid waiting on a egl fence before swapping buffers and rely on implicit sync on Intel GPUs: 938286
Applied Workarounds: rely_on_implicit_sync_for_swap_buffers
Disable GL_MESA_framebuffer_flip_y for desktop GL: 964010
Applied Workarounds: disable(GL_MESA_framebuffer_flip_y)
ANGLE Features
allowCompressedFormats (Frontend workarounds): Enabled: true
Allow compressed formats
cacheCompiledShader (Frontend features) anglebug:7036: Disabled
Enable to cache compiled shaders
disableAnisotropicFiltering (Frontend workarounds): Disabled
Disable support for anisotropic filtering
disableDrawBuffersIndexed (Frontend features) anglebug:7724: Disabled
Disable support for OES_draw_buffers_indexed and EXT_draw_buffers_indexed
disableProgramBinary (Frontend features) anglebug:5007: Disabled: IsPowerVrRogue(functions)
Disable support for GL_OES_get_program_binary
disableProgramCachingForTransformFeedback (Frontend workarounds): Disabled: IsAndroid() && isQualcomm
On some GPUs, program binaries don't contain transform feedback varyings
emulatePixelLocalStorage (Frontend features) anglebug:7279: Disabled: false
Emulate ANGLE_shader_pixel_local_storage using shader images
enableCaptureLimits (Frontend features) anglebug:5750: Disabled
Set the context limits like frame capturing was enabled
enableCompressingPipelineCacheInThreadPool (Frontend workarounds) anglebug:4722: Disabled: false
Enable compressing pipeline cache in thread pool.
enableProgramBinaryForCapture (Frontend features) anglebug:5658: Disabled
Even if FrameCapture is enabled, enable GL_OES_get_program_binary
forceDepthAttachmentInitOnClear (Frontend workarounds) anglebug:7246: Disabled
Force depth attachment initialization on clear ops
forceGlErrorChecking (Frontend features) https://issuetracker.google.com/220069903: Disabled
Force GL error checking (i.e. prevent applications from disabling error checking
forceInitShaderVariables (Frontend features): Disabled
Force-enable shader variable initialization
forceRobustResourceInit (Frontend features) anglebug:6041: Disabled
Force-enable robust resource init
loseContextOnOutOfMemory (Frontend workarounds): Enabled: true
Some users rely on a lost context notification if a GL_OUT_OF_MEMORY error occurs
scalarizeVecAndMatConstructorArgs (Frontend workarounds) 1165751: Disabled: false
Always rewrite vec/mat constructors to be consistent
RGBA4IsNotSupportedForColorRendering (OpenGL workarounds): Enabled: functions->standard == STANDARD_GL_DESKTOP && isIntel
GL_RGBA4 is not color renderable
RGBDXT1TexturesSampleZeroAlpha (OpenGL workarounds) anglebug:3729: Disabled: IsApple()
Sampling BLACK texels from RGB DXT1 textures returns transparent black on Mac.
addAndTrueToLoopCondition (OpenGL workarounds): Disabled: IsApple() && isIntel
Calculation of loop conditions in for and while loop has bug
adjustSrcDstRegionForBlitFramebuffer (OpenGL workarounds) 830046: Enabled: IsLinux() || (IsAndroid() && isNvidia) || (IsWindows() && isNvidia) || (IsApple() && functions->standard == STANDARD_GL_ES)
Many platforms have issues with blitFramebuffer when the parameters are large.
allowAstcFormats (OpenGL workarounds): Disabled: !isMesa || isIntel && (Is9thGenIntel(device) || IsGeminiLake(device) || IsCoffeeLake(device) || Is11thGenIntel(device) || Is12thGenIntel(device))
Enable ASTC on desktop OpenGL
allowClearForRobustResourceInit (OpenGL workarounds) 848952: Disabled: IsApple()
Using glClear for robust resource initialization is buggy on some drivers and leads to texture corruption. Default to data uploads except on MacOS where it is very slow.
allowETCFormats (OpenGL workarounds): Enabled: isIntel && !IsSandyBridge(device) && !IsIvyBridge(device) && !IsHaswell(device)
Enable ETC2/EAC on desktop OpenGL
alwaysCallUseProgramAfterLink (OpenGL workarounds) 110263: Enabled: true
Always call useProgram after a successful link to avoid a driver bug
alwaysUnbindFramebufferTexture2D (OpenGL workarounds) anglebug:5536: Disabled: isNvidia && (IsWindows() || IsLinux())
Force unbind framebufferTexture2D before binding renderbuffer to work around driver bug.
avoid1BitAlphaTextureFormats (OpenGL workarounds): Disabled: functions->standard == STANDARD_GL_DESKTOP && isAMD
Issue with 1-bit alpha framebuffer formats
bindTransformFeedbackBufferBeforeBindBufferRange (OpenGL workarounds) anglebug:5140: Disabled: IsApple()
Bind transform feedback buffers to the generic binding point before calling glBindBufferBase or glBindBufferRange.
clampArrayAccess (OpenGL workarounds) anglebug:2978: Disabled: IsAndroid() || isAMD || !functions->hasExtension("GL_KHR_robust_buffer_access_behavior")
Clamp uniform array access to avoid reading invalid memory.
clampFragDepth (OpenGL workarounds): Disabled: isNvidia
gl_FragDepth is not clamped correctly when rendering to a floating point depth buffer
clampMscRate (OpenGL workarounds) 1042393: Disabled: IsLinux() && IsWayland()
Some drivers return bogus values for GetMscRate, so we clamp it to 30Hz
clampPointSize (OpenGL workarounds): Disabled: IsAndroid() || isNvidia
The point size range reported from the API is inconsistent with the actual behavior
clearToZeroOrOneBroken (OpenGL workarounds) 710443: Disabled: IsApple() && isIntel && GetMacOSVersion() < OSVersion(10, 12, 6)
Clears when the clear color is all zeros or ones do not work.
clipSrcRegionForBlitFramebuffer (OpenGL workarounds) 830046: Disabled: IsApple() || (IsLinux() && isAMD)
Issues with blitFramebuffer when the parameters don't match the framebuffer size.
decodeEncodeSRGBForGenerateMipmap (OpenGL workarounds) anglebug:4646: Disabled: IsApple()
Decode and encode before generateMipmap for srgb format textures.
disableBlendFuncExtended (OpenGL workarounds) anglebug:1085: Enabled: isAMD || isIntel
ARB_blend_func_extended does not pass the tests
disableDrawBuffersIndexed (OpenGL workarounds): Disabled: IsWindows() && isAMD
Disable OES_draw_buffers_indexed extension.
disableGPUSwitchingSupport (OpenGL workarounds) 1091824: Disabled: isDualGPUMacWithNVIDIA
Disable GPU switching support (use only the low-power GPU) on older MacBook Pros.
disableMultisampledRenderToTexture (OpenGL workarounds) anglebug:2894: Disabled: isAdreno4xxOnAndroidLessThan51 || isAdreno4xxOnAndroid70 || isAdreno5xxOnAndroidLessThan70 || isAdreno5xxOnAndroid71 || isLinuxVivante
Many drivers have bugs when using GL_EXT_multisampled_render_to_texture
disableNativeParallelCompile (OpenGL workarounds) 1094869: Disabled: isTSANBuild && IsLinux() && isNvidia
Do not use native KHR_parallel_shader_compile even when available.
disableSemaphoreFd (OpenGL workarounds) 1046462: Disabled: IsLinux() && isAMD && isMesa && mesaVersion < (std::array<int, 3>{19, 3, 5})
Disable GL_EXT_semaphore_fd extension
disableSyncControlSupport (OpenGL workarounds) 1137851: Disabled: IsLinux() && isIntel && isMesa && mesaVersion[0] == 20
Speculative fix for issues on Linux/Wayland where exposing GLX_OML_sync_control renders Chrome unusable
disableTextureClampToBorder (OpenGL workarounds) anglebug:7405: Disabled: isImagination
Imagination devices generate INVALID_ENUM when setting the texture border color.
disableTimestampQueries (OpenGL workarounds) 811661: Disabled: (IsLinux() && isVMWare) || (IsAndroid() && isNvidia) || (IsAndroid() && GetAndroidSdkLevel() < 27 && IsAdreno5xxOrOlder(functions)) || (IsAndroid() && IsMaliT8xxOrOlder(functions)) || (IsAndroid() && IsMaliG31OrOlder(functions))
Disable GL_EXT_disjoint_timer_query extension
disableWorkerContexts (OpenGL workarounds) 849576: Disabled: (IsWindows() && (isIntel || isAMD)) || (IsLinux() && isNvidia) || IsIOS() || IsAndroid() || IsAndroidEmulator(functions)
Some tests have been seen to fail using worker contexts
doWhileGLSLCausesGPUHang (OpenGL workarounds) 644669: Disabled: IsApple() && functions->standard == STANDARD_GL_DESKTOP && GetMacOSVersion() < OSVersion(10, 11, 0)
Some GLSL constructs involving do-while loops cause GPU hangs
doesSRGBClearsOnLinearFramebufferAttachments (OpenGL workarounds): Enabled: isIntel || isAMD
Issue clearing framebuffers with linear attachments when GL_FRAMEBUFFER_SRGB is enabled
dontInitializeUninitializedLocals (OpenGL workarounds) anglebug:2046: Disabled: IsAndroid() && isQualcomm
Initializing uninitialized locals caused odd behavior in a few WebGL 2 tests
dontRelinkProgramsInParallel (OpenGL workarounds) anglebug:3045: Disabled: IsAndroid() || (IsWindows() && isIntel)
Relinking a program in parallel is buggy
dontUseLoopsToInitializeVariables (OpenGL workarounds) 809422: Disabled: (IsAndroid() && isQualcomm) || (isIntel && IsApple())
For loops used to initialize variables hit native GLSL compiler bugs
emulateAbsIntFunction (OpenGL workarounds) 642227: Disabled: IsApple() && isIntel
abs(i) where i is an integer returns unexpected result
emulateAtan2Float (OpenGL workarounds) 672380: Disabled: isNvidia
atan(y, x) may return a wrong answer
emulateCopyTexImage2D (OpenGL workarounds): Disabled: isApple
Replace CopyTexImage2D with TexImage2D + CopyTexSubImage2D.
emulateCopyTexImage2DFromRenderbuffers (OpenGL workarounds) anglebug:4674: Disabled: IsApple() && functions->standard == STANDARD_GL_ES && !(isAMD && IsWindows())
CopyTexImage2D spuriously returns errors on iOS when copying from renderbuffers.
emulateImmutableCompressedTexture3D (OpenGL workarounds) 1060012: Disabled: isQualcomm
Use non-immutable texture allocation to work around a driver bug.
emulateIsnanFloat (OpenGL workarounds) 650547: Disabled: isIntel && IsApple() && IsSkylake(device) && GetMacOSVersion() < OSVersion(10, 13, 2)
Using isnan() on highp float will get wrong answer
emulateMaxVertexAttribStride (OpenGL workarounds) anglebug:1936: Disabled: IsLinux() && functions->standard == STANDARD_GL_DESKTOP && isAMD
Some drivers return 0 when MAX_VERTEX_ATTRIB_STRIED queried
emulatePackSkipRowsAndPackSkipPixels (OpenGL workarounds) anglebug:4849: Disabled: IsApple()
GL_PACK_SKIP_ROWS and GL_PACK_SKIP_PIXELS are ignored in Apple's OpenGL driver.
emulatePrimitiveRestartFixedIndex (OpenGL workarounds) anglebug:3997: Disabled: functions->standard == STANDARD_GL_DESKTOP && functions->isAtLeastGL(gl::Version(3, 1)) && !functions->isAtLeastGL(gl::Version(4, 3))
When GL_PRIMITIVE_RESTART_FIXED_INDEX is not available, emulate it with GL_PRIMITIVE_RESTART and glPrimitiveRestartIndex.
emulateRGB10 (OpenGL workarounds) 1300575: Enabled: functions->standard == STANDARD_GL_DESKTOP
Emulate RGB10 support using RGB10_A2.
finishDoesNotCauseQueriesToBeAvailable (OpenGL workarounds): Disabled: functions->standard == STANDARD_GL_DESKTOP && isNvidia
glFinish doesn't cause all queries to report available result
flushBeforeDeleteTextureIfCopiedTo (OpenGL workarounds) anglebug:4267: Disabled: IsApple() && isIntel
Some drivers track CopyTex{Sub}Image texture dependencies incorrectly. Flush before glDeleteTextures in this case
flushOnFramebufferChange (OpenGL workarounds) 1181068: Disabled: IsApple() && Has9thGenIntelGPU(systemInfo)
Switching framebuffers without a flush can lead to crashes on Intel 9th Generation GPU Macs.
initFragmentOutputVariables (OpenGL workarounds) 1171371: Disabled: IsAdreno42xOr3xx(functions)
No init gl_FragColor causes context lost
initializeCurrentVertexAttributes (OpenGL workarounds): Disabled: isNvidia
During initialization, assign the current vertex attributes to the spec-mandated defaults
keepBufferShadowCopy (OpenGL workarounds): Disabled: !CanMapBufferForRead(functions)
Maintain a shadow copy of buffer data when the GL API does not permit reading data back.
limitMax3dArrayTextureSizeTo1024 (OpenGL workarounds) 927470: Disabled: limitMaxTextureSize
Limit max 3d texture size and max array texture layers to 1024 to avoid system hang
limitMaxMSAASamplesTo4 (OpenGL workarounds) 797243: Disabled: IsAndroid() || (IsApple() && (isIntel || isAMD || isNvidia))
Various rendering bugs have been observed when using higher MSAA counts
limitWebglMaxTextureSizeTo4096 (OpenGL workarounds) 927470: Disabled: IsAndroid() || limitMaxTextureSize
Limit webgl max texture size to 4096 to avoid frequent out-of-memory errors
packLastRowSeparatelyForPaddingInclusion (OpenGL workarounds) anglebug:1512: Disabled: IsApple() || isNvidia
When uploading textures from an pack buffer, some drivers count an extra row padding
packOverlappingRowsSeparatelyPackBuffer (OpenGL workarounds): Disabled: isNvidia
In the case of packing to a pixel pack buffer, pack overlapping rows row by row
passHighpToPackUnormSnormBuiltins (OpenGL workarounds) anglebug:7527: Disabled: isQualcomm
packUnorm4x8 fails on Pixel 4 if it is not passed a highp vec4.
preAddTexelFetchOffsets (OpenGL workarounds) 642605: Disabled: IsApple() && isIntel
Intel Mac drivers mistakenly consider the parameter position of nagative vaule as invalid even if the sum of position and offset is in range, so we need to add workarounds by rewriting texelFetchOffset(sampler, position, lod, offset) into texelFetch(sampler, position + offset, lod).
promotePackedFormatsTo8BitPerChannel (OpenGL workarounds) anglebug:5469: Disabled: IsApple() && hasAMD
Packed color formats are buggy on Macs with AMD GPUs
queryCounterBitsGeneratesErrors (OpenGL workarounds) anglebug:3027: Disabled: IsNexus5X(vendor, device)
Drivers generate errors when querying the number of bits in timer queries
readPixelsUsingImplementationColorReadFormatForNorm16 (OpenGL workarounds) anglebug:4214: Disabled: !isIntel && functions->standard == STANDARD_GL_ES && functions->isAtLeastGLES(gl::Version(3, 1)) && functions->hasGLESExtension("GL_EXT_texture_norm16")
Quite some OpenGL ES drivers don't implement readPixels for RGBA/UNSIGNED_SHORT from EXT_texture_norm16 correctly
reapplyUBOBindingsAfterUsingBinaryProgram (OpenGL workarounds) anglebug:1637: Disabled: isAMD || IsAndroid()
Some drivers forget about UBO bindings when using program binaries
regenerateStructNames (OpenGL workarounds) 403957: Disabled: IsApple()
All Mac drivers do not handle struct scopes correctly. This workaround overwrites a structname with a unique prefix.
removeDynamicIndexingOfSwizzledVector (OpenGL workarounds) 709351: Disabled: IsApple() || IsAndroid() || IsWindows()
Dynamic indexing of swizzled l-values doesn't work correctly on various platforms.
removeInvariantAndCentroidForESSL3 (OpenGL workarounds): Disabled: functions->isAtMostGL(gl::Version(4, 1)) || (functions->standard == STANDARD_GL_DESKTOP && isAMD)
Fix spec difference between GLSL 4.1 or lower and ESSL3
resetTexImage2DBaseLevel (OpenGL workarounds) 705865: Disabled: IsApple() && isIntel && GetMacOSVersion() >= OSVersion(10, 12, 4)
Reset texture base level before calling glTexImage2D to work around pixel comparison failure.
rewriteFloatUnaryMinusOperator (OpenGL workarounds) 308366: Disabled: IsApple() && isIntel && GetMacOSVersion() < OSVersion(10, 12, 0)
Using '-<float>' will get wrong answer
rewriteRepeatedAssignToSwizzled (OpenGL workarounds): Disabled: isNvidia
Repeated assignment to swizzled values inside a GLSL user-defined function have incorrect results
rewriteRowMajorMatrices (OpenGL workarounds) anglebug:2273: Disabled: false
Rewrite row major matrices in shaders as column major as a driver bug workaround
sanitizeAMDGPURendererString (OpenGL workarounds) 1181193: Disabled: IsLinux() && hasAMD
Strip precise kernel and DRM version information from amdgpu renderer strings.
setPrimitiveRestartFixedIndexForDrawArrays (OpenGL workarounds) anglebug:3997: Disabled: features->emulatePrimitiveRestartFixedIndex.enabled && IsApple() && isIntel
Some drivers discard vertex data in DrawArrays calls when the fixed primitive restart index is within the number of primitives being drawn.
setZeroLevelBeforeGenerateMipmap (OpenGL workarounds): Disabled: IsApple()
glGenerateMipmap fails if the zero texture level is not set on some Mac drivers.
shiftInstancedArrayDataWithOffset (OpenGL workarounds) 1144207: Disabled: IsApple() && IsIntel(vendor) && !IsHaswell(device)
glDrawArraysInstanced is buggy on certain new Mac Intel GPUs
supportsFragmentShaderInterlockARB (OpenGL features) anglebug:7279: Enabled: functions->isAtLeastGL(gl::Version(4, 5)) && functions->hasGLExtension("GL_ARB_fragment_shader_interlock")
Backend GL context supports ARB_fragment_shader_interlock extension
supportsFragmentShaderInterlockNV (OpenGL features) anglebug:7279: Enabled: functions->isAtLeastGL(gl::Version(4, 3)) && functions->hasGLExtension("GL_NV_fragment_shader_interlock")
Backend GL context supports NV_fragment_shader_interlock extension
supportsFragmentShaderOrderingINTEL (OpenGL features) anglebug:7279: Disabled: functions->isAtLeastGL(gl::Version(4, 4)) && functions->hasGLExtension("GL_INTEL_fragment_shader_ordering")
Backend GL context supports GL_INTEL_fragment_shader_ordering extension
supportsShaderFramebufferFetchEXT (OpenGL features) anglebug:7279: Disabled: functions->hasGLESExtension("GL_EXT_shader_framebuffer_fetch")
Backend GL context supports EXT_shader_framebuffer_fetch extension
supportsShaderFramebufferFetchNonCoherentEXT (OpenGL features) anglebug:7279: Disabled: functions->hasGLESExtension("EXT_shader_framebuffer_fetch_non_coherent")
Backend GL context supports EXT_shader_framebuffer_fetch_non_coherent extension
syncVertexArraysToDefault (OpenGL workarounds) anglebug:5577: Disabled: !nativegl::SupportsVertexArrayObjects(functions)
Only use the default VAO because of missing support or driver bugs
unbindFBOBeforeSwitchingContext (OpenGL workarounds) 1181193: Disabled: IsPowerVR(vendor)
Imagination GL drivers are buggy with context switching.
unfoldShortCircuits (OpenGL workarounds) anglebug:482: Disabled: IsApple()
Mac incorrectly executes both sides of && and || expressions when they should short-circuit.
unpackLastRowSeparatelyForPaddingInclusion (OpenGL workarounds) anglebug:1512: Disabled: IsApple() || isNvidia
When uploading textures from an unpack buffer, some drivers count an extra row padding
unpackOverlappingRowsSeparatelyUnpackBuffer (OpenGL workarounds): Disabled: isNvidia
In the case of unpacking from a pixel unpack buffer, unpack overlapping rows row by row
unsizedSRGBReadPixelsDoesntTransform (OpenGL workarounds) 550292: Disabled: IsAndroid() && isQualcomm
Drivers returning raw sRGB values instead of linearized values when calling glReadPixels on unsized sRGB texture formats
uploadTextureDataInChunks (OpenGL workarounds) 1181068: Disabled: IsApple()
Upload texture data in <120kb chunks to work around Mac driver hangs and crashes.
useUnusedBlocksWithStandardOrSharedLayout (OpenGL workarounds): Disabled: (IsApple() && functions->standard == STANDARD_GL_DESKTOP) || (IsLinux() && isAMD)
Unused std140 or shared uniform blocks will be treated as inactive
vertexIDDoesNotIncludeBaseVertex (OpenGL workarounds): Disabled: IsApple() && isAMD
gl_VertexID in GLSL vertex shader doesn't include base vertex value
DAWN Info
<CPU> Vulkan backend - SwiftShader Device (Subzero)
[Default Toggle Names]
lazy_clear_resource_on_first_use: https://crbug.com/dawn/145: Clears resource to zero on first usage. This initializes the resource so that no dirty bits from recycled memory is present in the new resource.
use_temporary_buffer_in_texture_to_texture_copy: https://crbug.com/dawn/42: Split texture-to-texture copy into two copies: copy from source texture into a temporary buffer, and copy from the temporary buffer into the destination texture when copying between compressed textures that don't have block-aligned sizes. This workaround is enabled by default on all Vulkan drivers to solve an issue in the Vulkan SPEC about the texture-to-texture copies with compressed formats. See #1005 (https://github.com/KhronosGroup/Vulkan-Docs/issues/1005) for more details.
vulkan_use_d32s8: https://crbug.com/dawn/286: Vulkan mandates support of either D32_FLOAT_S8 or D24_UNORM_S8. When available the backend will use D32S8 (toggle to on) but setting the toggle to off will make it use the D24S8 format when possible.
vulkan_use_s8: https://crbug.com/dawn/666: Vulkan has a pure stencil8 format but it is not universally available. When this toggle is on, the backend will use S8 for the stencil8 format, otherwise it will fallback to D32S8 or D24S8.
disallow_unsafe_apis: http://crbug.com/1138528: Produces validation errors on API entry points or parameter combinations that aren't considered secure yet.
use_vulkan_zero_initialize_workgroup_memory_extension: https://crbug.com/dawn/1302: Initialize workgroup memory with OpConstantNull on Vulkan when the Vulkan extension VK_KHR_zero_initialize_workgroup_memory is supported.
[WebGPU Forced Toggles - enabled]
disallow_spirv: https://crbug.com/1214923: Disallow usage of SPIR-V completely so that only WGSL is used for shader modules. This is useful to prevent a Chromium renderer process from successfully sending SPIR-V code to be compiled in the GPU process.
[Supported Features]
texture-compression-bc
texture-compression-etc2
texture-compression-astc
timestamp-query
depth-clip-control
depth32float-stencil8
indirect-first-instance
rg11b10ufloat-renderable
dawn-internal-usages
dawn-native
Version Information
Data exported
2023-02-11T23:53:25.967Z
Chrome version
Chrome/108.0.5359.98
Operating system
Linux 5.15.81
Software rendering list URL
https://chromium.googlesource.com/chromium/src/+/aa99c50ebc03bd334a4a8f11e99ab6fb5e0adf78/gpu/config/software_rendering_list.json
Driver bug list URL
https://chromium.googlesource.com/chromium/src/+/aa99c50ebc03bd334a4a8f11e99ab6fb5e0adf78/gpu/config/gpu_driver_bug_list.json
ANGLE commit id
unknown hash
2D graphics backend
Skia/108 7c55be996a81ff9c5c66984c9d4ef85d12a44c8c
Command Line
/nix/store/nq2g91pahhdvyw99kb18s9dh3csqg9my-chromium-unwrapped-108.0.5359.98/libexec/chromium/chromium --flag-switches-begin --flag-switches-end
Driver Information
Initialization time
235
In-process GPU
false
Passthrough Command Decoder
true
Sandboxed
false
GPU0
VENDOR= 0x0000 [Google Inc. (Intel)], DEVICE=0x0000 [ANGLE (Intel, Mesa Intel(R) UHD Graphics (TGL GT1), OpenGL 4.6 (Core Profile) Mesa 22.2.4)], DRIVER_VENDOR=Mesa, DRIVER_VERSION=22.2.4 *ACTIVE*
Optimus
false
AMD switchable
false
GPU CUDA compute capability major version
0
Pixel shader version
1.00
Vertex shader version
1.00
Max. MSAA samples
16
Machine model name
Machine model version
GL_VENDOR
Google Inc. (Intel)
GL_RENDERER
ANGLE (Intel, Mesa Intel(R) UHD Graphics (TGL GT1), OpenGL 4.6 (Core Profile) Mesa 22.2.4)
GL_VERSION
OpenGL ES 2.0.0 (ANGLE 2.1.0 git hash: unknown hash)
GL_EXTENSIONS
GL_AMD_performance_monitor GL_ANGLE_base_vertex_base_instance GL_ANGLE_base_vertex_base_instance_shader_builtin GL_ANGLE_client_arrays GL_ANGLE_compressed_texture_etc GL_ANGLE_depth_texture GL_ANGLE_framebuffer_blit GL_ANGLE_framebuffer_multisample GL_ANGLE_get_serialized_context_string GL_ANGLE_get_tex_level_parameter GL_ANGLE_instanced_arrays GL_ANGLE_logic_op GL_ANGLE_memory_size GL_ANGLE_multi_draw GL_ANGLE_program_cache_control GL_ANGLE_provoking_vertex GL_ANGLE_request_extension GL_ANGLE_robust_client_memory GL_ANGLE_texture_compression_dxt3 GL_ANGLE_texture_compression_dxt5 GL_ANGLE_texture_external_update GL_ANGLE_texture_rectangle GL_ANGLE_translated_shader_source GL_APPLE_clip_distance GL_ARB_sync GL_CHROMIUM_bind_generates_resource GL_CHROMIUM_bind_uniform_location GL_CHROMIUM_color_buffer_float_rgb GL_CHROMIUM_color_buffer_float_rgba GL_CHROMIUM_copy_texture GL_CHROMIUM_lose_context GL_CHROMIUM_sync_query GL_EXT_base_instance GL_EXT_blend_minmax GL_EXT_color_buffer_half_float GL_EXT_compressed_ETC1_RGB8_sub_texture GL_EXT_debug_label GL_EXT_debug_marker GL_EXT_discard_framebuffer GL_EXT_disjoint_timer_query GL_EXT_draw_buffers GL_EXT_draw_elements_base_vertex GL_EXT_float_blend GL_EXT_frag_depth GL_EXT_instanced_arrays GL_EXT_map_buffer_range GL_EXT_memory_object GL_EXT_memory_object_fd GL_EXT_multi_draw_indirect GL_EXT_multisample_compatibility GL_EXT_occlusion_query_boolean GL_EXT_read_format_bgra GL_EXT_robustness GL_EXT_sRGB GL_EXT_sRGB_write_control GL_EXT_semaphore GL_EXT_semaphore_fd GL_EXT_shader_texture_lod GL_EXT_shadow_samplers GL_EXT_texture_compression_bptc GL_EXT_texture_compression_dxt1 GL_EXT_texture_compression_rgtc GL_EXT_texture_compression_s3tc_srgb GL_EXT_texture_filter_anisotropic GL_EXT_texture_format_BGRA8888 GL_EXT_texture_norm16 GL_EXT_texture_rg GL_EXT_texture_sRGB_decode GL_EXT_texture_storage GL_EXT_texture_type_2_10_10_10_REV GL_EXT_unpack_subimage GL_KHR_debug GL_KHR_parallel_shader_compile GL_MESA_framebuffer_flip_y GL_NV_depth_buffer_float2 GL_NV_fence GL_NV_framebuffer_blit GL_NV_pack_subimage GL_NV_pixel_buffer_object GL_NV_read_depth GL_NV_read_stencil GL_OES_compressed_EAC_R11_signed_texture GL_OES_compressed_EAC_R11_unsigned_texture GL_OES_compressed_EAC_RG11_signed_texture GL_OES_compressed_EAC_RG11_unsigned_texture GL_OES_compressed_ETC1_RGB8_texture GL_OES_compressed_ETC2_RGB8_texture GL_OES_compressed_ETC2_RGBA8_texture GL_OES_compressed_ETC2_punchthroughA_RGBA8_texture GL_OES_compressed_ETC2_punchthroughA_sRGB8_alpha_texture GL_OES_compressed_ETC2_sRGB8_alpha8_texture GL_OES_compressed_ETC2_sRGB8_texture GL_OES_depth24 GL_OES_depth32 GL_OES_depth_texture GL_OES_draw_elements_base_vertex GL_OES_element_index_uint GL_OES_fbo_render_mipmap GL_OES_get_program_binary GL_OES_mapbuffer GL_OES_packed_depth_stencil GL_OES_rgb8_rgba8 GL_OES_standard_derivatives GL_OES_surfaceless_context GL_OES_texture_3D GL_OES_texture_border_clamp GL_OES_texture_float GL_OES_texture_float_linear GL_OES_texture_half_float GL_OES_texture_half_float_linear GL_OES_texture_npot GL_OES_texture_stencil8 GL_OES_vertex_array_object GL_WEBGL_video_texture
Disabled Extensions
GL_KHR_blend_equation_advanced GL_KHR_blend_equation_advanced_coherent GL_MESA_framebuffer_flip_y
Disabled WebGL Extensions
Window system binding vendor
Google Inc. (Intel)
Window system binding version
1.5 (ANGLE 2.1.0 git hash: unknown hash)
Window system binding extensions
EGL_KHR_create_context EGL_KHR_get_all_proc_addresses EGL_ANGLE_create_context_webgl_compatibility EGL_CHROMIUM_create_context_bind_generates_resource EGL_CHROMIUM_sync_control EGL_ANGLE_sync_control_rate EGL_EXT_pixel_format_float EGL_KHR_surfaceless_context EGL_ANGLE_display_texture_share_group EGL_ANGLE_display_semaphore_share_group EGL_ANGLE_create_context_client_arrays EGL_ANGLE_program_cache_control EGL_ANGLE_robust_resource_initialization EGL_ANGLE_create_context_extensions_enabled EGL_ANDROID_blob_cache EGL_ANDROID_recordable EGL_ANGLE_create_context_backwards_compatible EGL_KHR_create_context_no_error EGL_NOK_texture_from_pixmap EGL_KHR_reusable_sync
XDG_CURRENT_DESKTOP
none+xmonad
XDG_SESSION_TYPE
x11
GDMSESSION
none+xmonad
Ozone platform
x11
Direct rendering version
unknown
Reset notification strategy
0x8261
GPU process crash count
0
gfx::BufferFormats supported for allocation and texturing
R_8: not supported, R_16: not supported, RG_88: not supported, RG_1616: not supported, BGR_565: not supported, RGBA_4444: not supported, RGBX_8888: not supported, RGBA_8888: not supported, BGRX_8888: not supported, BGRA_1010102: not supported, RGBA_1010102: not supported, BGRA_8888: not supported, RGBA_F16: not supported, YVU_420: not supported, YUV_420_BIPLANAR: not supported, P010: not supported
Compositor Information
Tile Update Mode
One-copy
Partial Raster
Enabled
GpuMemoryBuffers Status
R_8
Software only
R_16
Software only
RG_88
Software only
RG_1616
Software only
BGR_565
Software only
RGBA_4444
Software only
RGBX_8888
Software only
RGBA_8888
Software only
BGRX_8888
Software only
BGRA_1010102
Software only
RGBA_1010102
Software only
BGRA_8888
Software only
RGBA_F16
Software only
YVU_420
Software only
YUV_420_BIPLANAR
Software only
P010
Software only
Display(s) Information
Info
Display[21691165392764996] bounds=[0,0 3840x2400], workarea=[0,0 3840x2400], scale=1, rotation=0, panel_rotation=0 internal.
Color space (all)
{primaries:BT709, transfer:SRGB, matrix:RGB, range:FULL}
Buffer format (all)
BGRA_8888
Color volume
{name:'srgb', r:[0.6400, 0.3300], g:[0.3000, 0.6000], b:[0.1500, 0.3300], w:[0.3127, 0.3290]}
SDR white level in nits
203
HDR relative maximum luminance
1
Bits per color component
8
Bits per pixel
24
Refresh Rate in Hz
59
Video Acceleration Information
Decoding
Decode h264 baseline
16x16 to 4096x4096 pixels
Decode h264 main
16x16 to 4096x4096 pixels
Decode h264 high
16x16 to 4096x4096 pixels
Decode vp8
16x16 to 4096x4096 pixels
Decode vp9 profile0
16x16 to 16384x16384 pixels
Decode vp9 profile2
16x16 to 16384x16384 pixels
Decode hevc main
16x16 to 16384x16384 pixels
Decode hevc main 10
16x16 to 16384x16384 pixels
Decode hevc main still-picture
16x16 to 16384x16384 pixels
Decode av1 profile main
16x16 to 16384x16384 pixels
Encoding
Vulkan Information
Device Performance Information
Log Messages
[1858585:1858585:0211/232104.502857:WARNING:sandbox_linux.cc(380)] : InitializeSandbox() called with multiple threads in process gpu-process.
[1858585:1858585:0211/234145.374942:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/234145.375064:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/234145.472058:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.472574:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.472770:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.472972:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.473111:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.473964:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.474153:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.474295:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.474451:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.474599:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.474739:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.474874:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.475011:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.475147:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.475869:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.476784:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.476967:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.477109:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.477248:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.477397:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.477564:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.477712:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.477858:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.478010:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.478149:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.479018:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.479208:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.479354:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.479524:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.479681:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.479829:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.479983:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.480136:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.480280:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.480443:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.481307:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.481504:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.481657:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.481805:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.481998:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.482229:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.482413:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.482587:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.482722:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.482859:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.483817:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.484022:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.484169:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.484315:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.484488:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.484623:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.484775:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.484887:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.485001:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.485104:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.486015:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.486163:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.486267:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.486377:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.486519:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.486642:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.486747:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.486840:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.486941:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.487083:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.487998:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.488196:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.488343:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.488500:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.488637:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.488785:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.489265:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.489548:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.489796:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.490028:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.491453:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.491695:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.491918:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.492140:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.492362:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.492624:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.492927:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.493165:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.493355:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.493516:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.494795:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.495075:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.495280:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.495463:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.495620:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.495771:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.497542:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.497807:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.498098:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.498257:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234145.631943:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/234145.632070:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/234146.170252:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/234146.170355:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/234146.523490:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/234146.523599:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/234146.560416:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234150.723272:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/234150.723417:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/234150.737067:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234207.688807:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/234207.688946:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/234213.092461:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/234213.092595:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/234213.123400:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234218.292369:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/234218.292525:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/234218.305831:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/234222.073241:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/234222.073365:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/234223.812997:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/234223.813131:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/234240.669524:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/234240.669723:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/235218.585448:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/235218.585586:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/235222.337372:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/235222.337522:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/235222.339168:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235222.350324:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235222.367798:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235222.385180:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235222.402502:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235222.419584:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235222.421363:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235222.422162:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235222.422436:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235222.422755:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235226.230783:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/235226.230894:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/235307.724218:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/235307.724384:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
[1858585:1858585:0211/235307.752809:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235307.754053:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235307.754875:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235307.755625:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235307.756357:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235307.757201:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235307.757925:ERROR:shared_image_manager.cc(202)] : SharedImageManager::ProduceSkia: Trying to Produce a Skia representation from a non-existent mailbox.
[1858585:1858585:0211/235308.645226:ERROR:shared_image_factory.cc(575)] : Could not find SharedImageBackingFactory with params: usage: DisplayRead|Scanout, format: YUV_420_BIPLANAR, share_between_threads: 0, gmb_type: platform
[1858585:1858585:0211/235308.645332:ERROR:shared_image_stub.cc(147)] : SharedImageStub: Unable to create shared image
#+end_src
https://www.lifewire.com/hardware-acceleration-in-chrome-4125122
Somehow resolved after disabling offloading. Also running chrome as =DISABLE_LAYER_AMD_SWITCHABLE_GRAPHICS_1=1 chromium=.
**** DONE Debug Chrome
See https://github.com/NixOS/nixpkgs/issues/216361
#+begin_src text
libGL error: MESA-LOADER: failed to open iris: /nix/store/lqz6hmd86viw83f9qll2ip87jhb7p1ah-glibc-2.35-224/lib/libc.so.6: version `GLIBC_2.36' not found (required by /nix/store/hvi95rrzrnqqhwvfn5b10l5c3f2lhr0h-llvm-15.0.7-lib/lib/libLLVM-15.so) (search paths /run/opengl-driver/lib/dri, suffix _dri)
libGL error: failed to load driver: iris
libGL error: MESA-LOADER: failed to open iris: /nix/store/lqz6hmd86viw83f9qll2ip87jhb7p1ah-glibc-2.35-224/lib/libc.so.6: version `GLIBC_2.36' not found (required by /nix/store/hvi95rrzrnqqhwvfn5b10l5c3f2lhr0h-llvm-15.0.7-lib/lib/libLLVM-15.so) (search paths /run/opengl-driver/lib/dri, suffix _dri)
libGL error: failed to load driver: iris
libGL error: MESA-LOADER: failed to open swrast: /nix/store/lqz6hmd86viw83f9qll2ip87jhb7p1ah-glibc-2.35-224/lib/libc.so.6: version `GLIBC_2.36' not found (required by /nix/store/hvi95rrzrnqqhwvfn5b10l5c3f2lhr0h-llvm-15.0.7-lib/lib/libLLVM-15.so) (search paths /run/opengl-driver/lib/dri, suffix _dri)
libGL error: failed to load driver: swrast
[3436:3436:0622/194103.267052:ERROR:angle_platform_impl.cc(43)] Display.cpp:1014 (initialize): ANGLE Display::initialize error 12289: Could not create a backing OpenGL context.
ERR: Display.cpp:1014 (initialize): ANGLE Display::initialize error 12289: Could not create a backing OpenGL context.
[3436:3436:0622/194103.268458:ERROR:gl_display.cc(504)] EGL Driver message (Critical) eglInitialize: Could not create a backing OpenGL context.
[3436:3436:0622/194103.268557:ERROR:gl_display.cc(917)] eglInitialize OpenGL failed with error EGL_NOT_INITIALIZED, trying next display type
[3436:3436:0622/194103.271814:ERROR:angle_platform_impl.cc(43)] Display.cpp:1014 (initialize): ANGLE Display::initialize error 12289: Could not create a backing OpenGL context.
ERR: Display.cpp:1014 (initialize): ANGLE Display::initialize error 12289: Could not create a backing OpenGL context.
[3436:3436:0622/194103.271908:ERROR:gl_display.cc(504)] EGL Driver message (Critical) eglInitialize: Could not create a backing OpenGL context.
#+end_src
Resolved by disabling offloading.
*** Chromium
#+begin_src nix :noweb yes :noweb-ref browser-chromium
programs.chromium = {
enable = true;
package = pkgs-bleeding.chromium;
commandLineArgs = [
# https://www.linuxuprising.com/2018/08/how-to-enable-hardware-accelerated.html
"--enable-accelerated-video-decode"
"--enable-logging=stderr"
"--ignore-gpu-blocklist"
"--use-gl=desktop"
"--enable-features=VaapiVideoEncoder,VaapiVideoDecoder"
"--disable-features=UseChromeOSDirectVideoDecoder"
# https://github.com/NixOS/nixpkgs/issues/209101
"--disable-gpu-vsync"
"--disable-frame-rate-limit"
# https://wiki.archlinux.org/title/chromium
"--ignore-gpu-blocklist"
"--enable-gpu-rasterization"
"--enable-zero-copy"
];
extensions = [
<<browser-chromium-extensions>>
];
};
#+end_src
See https://chromium.googlesource.com/chromium/src/+/refs/heads/main/chrome/common/chrome_switches.cc and https://source.chromium.org/search?q=file:switches.cc&ss=chromium%2Fchromium%2Fsrc for some switches that we can use according to the =commandLineArgs= option in [[https://github.com/nix-community/home-manager/blob/master/modules/programs/chromium.nix][programs/chromium.nix]].
**** Setting environment variable to disable switching
Note how https://github.com/NixOS/nixpkgs/issues/211408 outlines a fix regarding graphics switching/offloading:
#+begin_src bash
DISABLE_LAYER_AMD_SWITCHABLE_GRAPHICS_1=1
#+end_src
We set this through the =home.sessionVariables= option, so we can just run =chromium= to keep things simple:
#+begin_src nix :noweb yes :noweb-ref browser-chromium
home.sessionVariables.DISABLE_LAYER_AMD_SWITCHABLE_GRAPHICS_1 = 1;
#+end_src
**** Debugging
https://www.chromium.org/developers/how-tos/run-chromium-with-flags/
chrome://version
chrome://flags
chrome://gpu
**** COMMENT Chromium Overlay
See https://discourse.nixos.org/t/failed-vaapi-init/23317/3
#+begin_src nix :noweb-ref linux-overlays
chromium = super.chromium.override {
commandLineArgs = "--enable-features=VaapiVideoEncoder,VaapiVideoDecoder --use-gl=desktop --ignore-gpu-blocklist --enable-accelerated-video-decode";
};
#+end_src
**** Extensions
***** COMMENT Metamask
#+begin_src nix :noweb-ref browser-chromium-extensions
{
# Metamask
# https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn
id = "nkbihfbeogaeaoehlefnkodbefgpgknn";
}
#+end_src
***** Vimium
vi-like navigation of the browser
#+begin_src nix :noweb-ref browser-chromium-extensions
{
# Vimium
# https://chrome.google.com/webstore/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb
id = "dbepggeogbaibhgnhhndojpepiihcmeb";
}
#+end_src
- =c= :: enter caret mode from either of the visual modes (=v= visual mode, =V= visual line mode)
***** Wasavi
vi-editor for input controls
- enter with =C-RET=, exit with =:q= (typical vi exit command)
#+begin_src nix :noweb-ref browser-chromium-extensions
{
# wasavi
# https://chrome.google.com/webstore/detail/wasavi/dgogifpkoilgiofhhhodbodcfgomelhe
# see https://github.com/philc/vimium/issues/2564
id = "dgogifpkoilgiofhhhodbodcfgomelhe";
}
#+end_src
*** Firefox
#+begin_quote
[!TIP]
⚠️ In order to get the extensions in Firefox to work, you may have to first manually enable the extensions.
#+end_quote
**** Install Firefox on Linux
#+begin_src nix :noweb yes :noweb-ref browser-firefox
programs.firefox = {
enable = true;
<<browser-firefox-profiles>>
};
#+end_src
**** Install Firefox from Homebrew on macOS
#+begin_src nix :noweb-ref homebrew-casks
"firefox@developer-edition"
#+end_src
**** Extensions
#+begin_src nix :noweb yes :noweb-ref browser-firefox-profiles
# NOTE: Extensions need firefox.profiles to be defined
profiles.personal.extensions =
# https://nur.nix-community.org/repos/rycee/
with nur.repos.rycee.firefox-addons; [
<<browser-firefox-extensions>>
];
#+end_src
***** Tridactyl
Tridactyl is the extension introducing the vim bindings into Firefox. It will hijack the body of your new tabs which can bit a bit disruptive to your workflow as it will present a Tridactyl start page which is visually quite busy therefore running =:set newtab about:blank= to clear the body of the new tab can improve the UX and run =:set theme dark= to switch to a dark theme if new tabs are blasting you with white light.
#+begin_src nix :noweb-ref browser-firefox-extensions
multi-account-containers # needed by tridactyl
tridactyl
#+end_src
****** Escape Hatch
Remember that =<C-,>= (as described in the Tridactyl documentation which would be =C-,= in Emacs bindings notation or more simply but =Ctrl= + =,=) is the Tridactyl /escape hatch/ that gets you into a part within the page view of the browser where you can use the vi-like bindings to navigate or do this.
💡 This is convenient because loading some pages will leave the focus on the URL bar or the search bar and tabbing through may be a tedious way to get to the page view.
****** Ignore mode
Remember that =Shift= + =Insert= (or =Ctrl= + =Alt= + =Escape= but I'm refusing to learn that one because it is quite a dragon of a maneuver to efficiently pull of) will toggle to ignore mode in which all keypresses are passed-through to the web application.
💡 This is convenient for applications that have their own bindings that may conflict with Tridactyl.
****** Search
Use =/= to enter a search query and use =Ctrl= + =g= or =Ctrl= + =G= to cycle through search results.
💡 The search cycling binding is a bit differnet to what vi-bindings users may expect so just pay attention to keep =C-g= and =C-G= (expressed in Emacs notation) within (muscle) memory.
*** COMMENT Arc
@KKarpac has been hyping up this browser so much, I'll have to give it a shot, so here goes:
Update <2025-06-26 Thu>: It's [[https://www.reddit.com/r/ArcBrowser/comments/1ih3qzi/is_arc_dead_if_so_where_to_next/][dead]]!
#+begin_src nix :noweb-ref homebrew-casks
"arc"
#+end_src
*** COMMENT Zen
[[https://zen-browser.app/][Zen Browser]] was the open-source answer to the Arc Browser back then before Arc restarted from scratch.
#+begin_src nix :noweb-ref homebrew-casks
"zen-browser"
#+end_src
*** Shared Extensions
**** WIP GhostText
Use GhostText to edit text in the browser through a text editor.
just trying this out to edit text in browser in Emacs
https://chrome.google.com/webstore/detail/ghosttext/godiecgffnchndlihlpaajjcplehddca/related
#+begin_src nix :noweb-ref browser-chromium-extensions
{
# GhostText
# https://chrome.google.com/webstore/detail/ghosttext/godiecgffnchndlihlpaajjcplehddca
# see https://ghosttext.fregante.com/
id = "godiecgffnchndlihlpaajjcplehddca";
}
#+end_src
**** Darkreader
#+begin_src nix :noweb-ref browser-chromium-extensions
{
# Darkreader
# https://chrome.google.com/webstore/detail/dark-reader/eimadpbcbfnmbkopoojfekhnkhdbieeh
id = "eimadpbcbfnmbkopoojfekhnkhdbieeh";
}
#+end_src
#+begin_src nix :noweb-ref browser-firefox-extensions
darkreader
#+end_src
***** Override for mermaid on GitHub
/html/body/div[1]/div/div/svg/g[2]/rect
#entity-Document-5b2ba057-c937-56df-837d-8bac67f835ce > rect
GitHub wraps mermaid diagrams in a div with the .mermaid class:
#+begin_src css
div.mermaid svg#diagram rect.er.entityBox {
fill: transparent !important;
}
#+end_src
More generally and for the Mermaid Live editor the following applies added up top:
#+begin_src css :noweb yes
<<darkreader-mermaid>>
#+end_src
We fix the navigation controls for embedded mermaid diagrams by setting the fill and background clors on the control-panel buttons:
#+begin_src css :noweb-ref darkreader-mermaid
div.mermaid-viewer-control-panel .btn {
fill: var(--darkreader-neutral-text);
background-color: var(--darkreader-neutral-background);
}
#+end_src
For the ER diagrams:
#+begin_src css :noweb-ref darkreader-mermaid
svg g rect.er {
fill: var(--darkreader-neutral-background) !important;
}
svg g rect.er.entityBox {
fill: var(--darkreader-neutral-background) !important;
}
svg g rect.er.attributeBoxOdd {
fill: var(--darkreader-neutral-background) !important;
}
svg g rect.er.attributeBoxEven {
fill-opacity: 0.8 !important;
fill: var(--darkreader-selection-background);
}
svg rect.er.relationshipLabelBox {
fill: var(--darkreader-neutral-background) !important;
}
#+end_src
For the Flow diagrams:
#+begin_src css :noweb-ref darkreader-mermaid
svg g g.nodes rect, svg g g.nodes polygon {
fill: var(--darkreader-neutral-background) !important;
}
#+end_src
For Gantt diagrams:
#+begin_src css :noweb-ref darkreader-mermaid
svg g rect.task {
fill: var(--darkreader-selection-background) !important;
}
#+end_src
For Sequence diagrams:
#+begin_src css :noweb-ref darkreader-mermaid
svg line.messageLine0, svg line.messageLine1 {
stroke: var(--darkreader-neutral-text) !important;
}
div.mermaid .actor {
fill: var(--darkreader-neutral-background) !important;
}
div.mermaid .sequenceNumber {
color: var(--darkreader-selection-text) !important;
}
#+end_src
Filed into https://github.com/darkreader/darkreader/pull/11108
***** DXOS Overides
#+begin_src css :noweb-ref darkreader-mermaid
.sidebar {
background: var(--darkreader-neutral-background) !important;
}
#+end_src
** Chat
*** Discord
#+begin_src nix :noweb-ref desktop-packages
pkgs.discord
#+end_src
#+begin_src nix :noweb-ref nixpkgs-unfree
"discord"
"discord-ptb"
"discord-canary"
#+end_src
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"discord"
#+end_src
**** COMMENT Skip Discord host update
Tangle single block in order to configure file:~/.config/discord/settings.json such that Discord skips the host update logic as host updates won't work well on NixOS.
#+begin_src json :tangle ~/.config/discord/settings.json
{
"SKIP_HOST_UPDATE": true
}
#+end_src
*** Signal
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"signal"
#+end_src
*** Slack
Using Slack from the browser is a shitty experience because one has to keep so many tabs open for the different workspaces. I'm finally budging and installing the official client.
#+begin_src nix :noweb-ref desktop-packages
pkgs.slack
#+end_src
#+begin_src nix :noweb-ref nixpkgs-unfree
"slack"
#+end_src
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"slack"
#+end_src
*** Telegram
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"telegram"
#+end_src
*** WhatsApp
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"whatsapp"
#+end_src
*** Zoom
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"zoom"
#+end_src
** Docs
#+begin_src nix :tangle doc.nix :noweb yes
# Tangled from README.org
{ config, pkgs, ... }:
let
<<doc-let-bindings>>
in
{
home.packages = with pkgs; [
<<doc-packages>>
];
}
#+end_src
*** $LaTeX$
#+begin_src nix :noweb yes :noweb-ref doc-let-bindings
texlive-asabina = with pkgs; (texlive.combine {
inherit (texlive)
scheme-medium
luatex
atenddvi
background
bashful
capt-of
collection-basic
collection-fontsrecommended
collection-langeuropean
collection-langgerman
collection-latexrecommended
datetime
draftwatermark
enumitem
eso-pic
etoolbox
everypage
fmtcount
koma-script
lastpage
latexdiff
mdframed
needspace
numprint
paracol
pdfcrop
pgfgantt
soul
svg
tableof
titlepic
tocloft
transparent
trimspaces
ulem
wrapfig
xargs
xetex
xstring
xtab
;
});
#+end_src
#+begin_src nix :noweb yes :noweb-ref doc-packages
biber
bibtex2html
texlive-asabina
#+end_src
*** PDF
**** Utilities
***** pdftk
We install pdftk into our common config.
#+begin_src nix :noweb yes :noweb-ref doc-packages
pdftk
#+end_src
And relist it for the Darwin config
#+begin_src nix :noweb yes :noweb-ref nix-darwin-packages-common
pdftk
#+end_src
until I've had some time to properly abstract this mess of a config. I have my Linux machine back, so high-time to test that tux config again.
***** pandoc
#+begin_src nix :noweb yes :noweb-ref doc-packages
pandoc
#+end_src
**** Readers
***** Evince
#+begin_src nix :noweb yes :noweb-ref doc-packages
evince
#+end_src
***** Okular
#+begin_src nix :noweb yes :noweb-ref doc-packages
okular
#+end_src
***** Xournal
#+begin_src nix :noweb yes :noweb-ref doc-packages
xournal
#+end_src
***** Zathura
#+begin_src nix :noweb yes :noweb-ref doc-packages
zathura
#+end_src
*** Dictionaries
**** Aspell
#+begin_src nix :noweb yes :noweb-ref doc-packages
aspell
aspellDicts.de
aspellDicts.en
aspellDicts.nl
#+end_src
**** Hunspell
Install hunspell as the system-wide spell checker as we will use it in Emacs.
#+begin_src nix :noweb yes :noweb-ref nix-darwin-packages-common
hunspell
#+end_src
***** Hunspell dictionaries for MacOS
Set a few dictionaries that would be helpful to have in hunspell:
#+begin_src nix :noweb yes :noweb-ref nix-darwin-packages-common
hunspellDicts.nl_NL
hunspellDicts.en_US
hunspellDicts.de_DE
hunspellDicts.he_IL
hunspellDicts.es-any
hunspellDicts.fr-any
#+end_src
and set the path such that =hunspell -D= can actually find these dictionaries:
#+begin_src nix :noweb-ref nix-darwin
environment.pathsToLink = [ "/share/myspell" "/share/hunspell" ];
#+end_src
***** TODO COMMENT Hunspell dictionaries in NixOS
Figure out how to fix this configuration to reuse it in Darwin and Linux.
#+begin_src nix :noweb yes :noweb-ref doc-let-bindings
hunspell-personal = with prev;
(hunspellWithDicts with hunspellDicts; [
de_DE
en_US-large
(stdenv.mkDerivation rec {
pname = "hunspell-dict-nl-opentaal";
version = "2.20.19";
src = fetchFromGitHub {
owner = "OpenTaal";
repo = "opentaal-hunspell";
rev = "${version}";
sha256 = "sha256-/rYufNGkXWH7UQDa8ZI55JtP9LM+0j7Pad8zm2tFqko=";
};
meta = {
description = "Dutch dictionary for spelling checker Hunspell and Nuspell";
homepage = "https://github.com/OpenTaal/opentaal-hunspell";
license = {
fullName = "Revised BSD License and/or CC BY 3.0";
url = "https://github.com/OpenTaal/opentaal-hunspell/blob/${version}/LICENSE.txt";
};
maintainers = with maintainers; [ ];
platforms = lib.platforms.all;
};
dictFileName = "nl";
installPhase = ''
# hunspell dicts
install -dm755 "$out/share/hunspell"
install -m644 ${dictFileName}.dic "$out/share/hunspell/"
install -m644 ${dictFileName}.aff "$out/share/hunspell/"
# myspell dicts symlinks
install -dm755 "$out/share/myspell/dicts"
ln -sv "$out/share/hunspell/${dictFileName}.dic" "$out/share/myspell/dicts/"
ln -sv "$out/share/hunspell/${dictFileName}.aff" "$out/share/myspell/dicts/"
runHook postInstall
'';
})
]).overrideAttrs (old: {
buildCommand = ''
${old.buildCommand}
cp -r ${hunspell.man}/share $out/share
'';
});
#+end_src
#+begin_src nix :noweb yes :noweb-ref doc-packages
hunspell
#+end_src
*** Spreadsheets
#+begin_src nix :noweb yes :noweb-ref doc-packages
sc-im
visidata
#+end_src
*** COMMENT Completions
#+begin_src nix :noweb yes :noweb-ref doc-packages
#+end_src
*** Docs / Notes / Productivity / Office
**** Office
#+begin_src nix :noweb yes :noweb-ref doc-packages
libreoffice
#+end_src
**** COMMENT Notion
For work, we may need Notion installed on our MacOS systems:
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"notion"
#+end_src
**** Gdrive
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"google-drive"
#+end_src
**** Obsidian
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"obsidian" # best-in-class with mobile app support
#+end_src
**** Linear
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"linear"
#+end_src
**** Remarkable
We previously installed the reMarkable app for OSX through homebrew casks but are now following the recommendation from the app itself to install it from the App Store.
https://apps.apple.com/us/app/remarkable-desktop/id1276493162
#+begin_src nix :noweb-ref homebrew-masapps :noweb yes
"Remarkable Desktop" = 1276493162;
#+end_src
*** Misc
**** Endel
[[https://endel.io/][Endel]] is a wellness app which helps play soundscapes to help one fall asleep, focus, relax, etc. I have been using the Endel app on Android for a while now but there is also the Mac app available from the [[https://apps.apple.com/de/app/endel-focus-sleep-relax/id1346247457?l=en-GB][Apple App Store]].
#+begin_src nix :noweb-ref homebrew-masapps :noweb yes
"Endel" = 1346247457;
#+end_src
**** QR
#+begin_src nix :noweb yes :noweb-ref doc-packages
qrencode
#+end_src
**** Amphetamine
https://apps.apple.com/de/app/amphetamine/id937984704?l=en-GB&mt=12b
#+begin_src nix :noweb-ref homebrew-masapps :noweb yes
"Amphetamine"= 937984704;
#+end_src
** Programming Languages
** AI
*** Claude
**** Claude Desktop
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"claude"
#+end_src
**** Claude Code
See [[https://www.npmjs.com/package/@anthropic-ai/claude-code][NPM]] or [[https://github.com/anthropics/claude-code][GitHub]] for the Claude Code CLI tool.
Installed via Homebrew cask rather than nixpkgs. Claude Code's release cadence (~90 versions between nixpkgs-unstable and upstream as of <2026-07-06 Sun>) makes nixpkgs impractical — features like model selection (Fable requires ≥2.1.170) ship weeks before nixpkgs catches up. Homebrew tracks upstream closely (91K installs/month) and the =claude-code= cask is maintained by the community.
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"claude-code"
#+end_src
***** Skills, agents, and slash commands
I manage my Claude Code skills (and eventually agents and slash commands) from this repo under =claude/=. The =claude/skills/= directory is symlinked into =~/.claude/skills= as an out-of-store symlink so that editing a =SKILL.md= is immediately visible to Claude without needing a =home-manager switch= between iterations.
Only the specific subpaths I own are symlinked — runtime state like =history.jsonl=, =sessions/=, =projects/=, =todos/=, and =shell-snapshots/= stays untouched under =~/.claude/=. If I want to add =agents/= or =commands/= later, they each get their own =home.file= entry alongside this one rather than symlinking =~/.claude= as a whole.
****** Skill sources
Some skills are authored directly in this repo (=context7-mcp=, =dispatch=, =qsearch=, =troubleshoot=, =untypo=). Others live canonically in external repos and are resolved via local symlinks — not tracked in git, since the paths are machine-specific.
After cloning, create these symlinks manually:
#+begin_src bash :eval no
# Engineering skills from the KB repo (asabina-de/kb)
ln -s /path/to/kb/skills/commenting claude/skills/commenting
ln -s /path/to/kb/skills/commitmsg claude/skills/commitmsg
ln -s /path/to/kb/skills/designnote claude/skills/designnote
ln -s /path/to/kb/skills/linearissue claude/skills/linearissue
ln -s /path/to/kb/skills/pairprog claude/skills/pairprog
ln -s /path/to/kb/skills/pr claude/skills/pr
# Project-specific skills from other repos
ln -s /path/to/philipps-byrne/claude/skills/techddreport claude/skills/techddreport
#+end_src
These symlinks are followed by the =mkOutOfStoreSymlink= chain — =~/.claude/skills/= points to this directory, and the symlinks within resolve to the external repos. Editing a skill in the KB repo is immediately visible to Claude Code.
#+begin_src nix :noweb-ref home-darwin-home-file
".claude/skills".source = config.lib.file.mkOutOfStoreSymlink "${dotfilesPath}/claude/skills";
#+end_src
Note the =${dotfilesPath}/...= interpolation rather than a relative path literal =./claude/skills=. Under a flake-based nix-darwin setup, =./claude/skills= gets coerced to a store path at evaluation time — the "out of store" symlink ends up pointing into =/nix/store/...-source/claude/skills=, which defeats the whole purpose of live editing. Using a string-interpolated absolute path via the =dotfilesPath= module argument (defined in =machines.nix= per host) sidesteps this coercion and produces a symlink that points at the real working tree. The same fix is already applied for =~/.emacs.d=; other =mkOutOfStoreSymlink= uses in this config (=ranger=, =direnvrc=, =git/ignore=, =ghostty=, =hammerspoon=) still use the broken pattern and should be migrated in a follow-up.
We also track our Claude settings file such that we can reproduce our setup relatively quickly on our next machine. Note that imperative changes, like plugins installation through the =/plugin= Claude command will trigger changes here that we will need to track in Claude.
#+begin_src nix :noweb-ref home-darwin-home-file
".claude/settings.json".source = config.lib.file.mkOutOfStoreSymlink "${dotfilesPath}/claude/settings.json";
#+end_src
Global Claude rules (=~/.claude/rules/=) are personal behavioral guidance that applies across all projects on this machine. Tracked here so they survive machine rebuilds.
#+begin_src nix :noweb-ref home-darwin-home-file
".claude/rules".source = config.lib.file.mkOutOfStoreSymlink "${dotfilesPath}/claude/rules";
#+end_src
#+begin_quote org
[!WARNING]
Pay attention to what ends up making its way to =~/.claude/settings.json= as you don't ever want secrets to make it into this repo.
#+end_quote
*** OpenCode
[[https://github.com/anomalyco/opencode][OpenCode]] is an alternative AI coding agent. Its config lives at =~/.config/opencode/=. We track the config and plugins in =opencode/= and symlink them into place, following the same pattern as Claude Code.
**** Config layout
OpenCode looks for config in [[https://github.com/anomalyco/opencode/blob/dev/packages/core/src/config.ts][multiple locations]], in priority order: global (=~/.config/opencode/opencode.jsonc=), project-level (=./opencode.jsonc= or =./.opencode/=), and env overrides (=OPENCODE_CONFIG=, =OPENCODE_CONFIG_CONTENT=). We manage the global config here. The file format is JSONC with a =$schema= field pointing to =https://opencode.ai/config.json=.
We symlink =opencode.jsonc= and =plugins/= into =~/.config/opencode/= via nix. The remaining files in that directory (=package.json=, =package-lock.json=, =node_modules/=, =.gitignore=) are [[https://github.com/anomalyco/opencode/blob/dev/packages/opencode/src/config/config.ts][auto-generated by OpenCode at startup]] — it installs =@opencode-ai/plugin= (the plugin SDK, version-matched to the running binary) into each config directory. These auto-generated files are not tracked in dotfiles.
#+begin_src nix :noweb-ref home-darwin-home-file
# OpenCode config and plugins
".config/opencode/opencode.jsonc".source = config.lib.file.mkOutOfStoreSymlink "${dotfilesPath}/opencode/opencode.jsonc";
".config/opencode/plugins".source = config.lib.file.mkOutOfStoreSymlink "${dotfilesPath}/opencode/plugins";
#+end_src
**** Plugins
OpenCode [[https://github.com/anomalyco/opencode/blob/dev/packages/web/src/content/docs/plugins.mdx][auto-discovers plugins]] from =plugins/*.{ts,js}= (or =plugin/*.{ts,js}=) in any config directory. Single-file plugins load without a =package.json=; directory-style plugins need either a =package.json= or an =index.ts= inside the subdirectory.
Plugins are TypeScript modules that export a default function returning a hooks object. The [[https://github.com/anomalyco/opencode/blob/dev/packages/plugin/src/index.ts][plugin API]] provides these lifecycle hooks:
| Hook | Fires when |
|------+------------|
| =chat.message= | User submits a message (equivalent to Claude Code's =UserPromptSubmit=) |
| =tool.execute.before= | Before any tool call (equivalent to =PreToolUse=) |
| =tool.execute.after= | After a tool call completes (equivalent to =PostToolUse=) |
| =chat.params= | Before LLM call — can modify temperature, max tokens |
| =chat.headers= | Before LLM call — can modify HTTP headers |
| =shell.env= | Inject/modify env vars for all shell executions |
| =event= | Every internal event (session, message, tool, file, LSP, etc.) |
| =dispose= | Plugin teardown |
Plugins run in-process (Bun runtime) — they are TypeScript functions, not shell scripts. This means they have access to =bun:sqlite=, =process.cwd()=, and the full Node API.
**Worklog plugin:** =plugins/worklog.ts= hooks =chat.message= to record heartbeats to =~/.claude/worklog.db= with =source='opencode'=. It uses the same project-resolution logic as the Claude Code hook (=.worklog-project= file → git remote heuristic → directory name fallback).
**** Anthropic Tools
In order to use [[https://platform.claude.com/docs/en/managed-agents/quickstart#homebrew-(macos)]Claude Managed Agents] for background work, we're installing ant:
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"anthropics/tap/ant"
#+end_src
**** Claude Code for VSCode
For vscode and vscode-derived editors, we want to enable the official Claude Code extension. On <2026-02-07 Sat>, we isolated and commented out just the installation part of this config in order to manage this extension manually in vscode.
***** COMMENT Install vscode extension for Claude Code with nix
#+begin_src nix :noweb-ref vscode-extensions
anthropic.claude-code
#+end_src
#+begin_src nix :noweb-ref darwin-unfree
"vscode-extension-anthropic-claude-code"
#+end_src
***** Configure vscode extension for Claude Code
We prefer Claude Code in a panel, so let's set that up so it will be honored in our settings:
#+begin_src nix :noweb-ref vscode-settings
"claudeCode.preferredLocation" = "panel";
#+end_src
*** Superwhisper
[[https://superwhisper.com][Superwhisper]] is a macOS voice dictation tool built on Whisper with direct Claude Code and Claude Desktop integration (v2.13.0+, April 2026). It uses macOS accessibility APIs for context-aware transcription across modes ranging from fully offline (local Whisper/Parakeet) to cloud-assisted LLM post-processing. Selected in [[https://linear.app/asabina/issue/VID-640][VID-640]] research as the best fit for a Claude-heavy workflow.
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"superwhisper"
#+end_src
**** Granola
[[https://granola.ai][Granola]] is an AI meeting notepad for macOS that passively captures audio during meetings and generates structured notes.
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"granola"
#+end_src
*** Gemini
#+begin_src nix :noweb-ref dev-packages
pkgs.gemini-cli
#+end_src
*** OpenAI
**** ChatGPT
ChatGPT is the premiere LLM tool that I've been using. On some systems (tokyo23), I installed it manually, but let's add it to my config since I'm realising how much I'm depending on the nifty Option+Space shortcut these days.
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
(if pkgs.stdenv.hostPlatform.system == "aarch64-darwin" then "chatgpt" else null)
#+end_src
**** OpenAI Codex CLI
Use [[https://github.com/openai/codex][Codex]] as a coding agent, directly from your CLI:
#+begin_src nix :noweb-ref dev-packages
pkgs.codex
#+end_src
**** COMMENT OpenAI Codex VsCode Extension
https://marketplace.visualstudio.com/items?itemName=openai.chatgpt
#+begin_src nix :noweb-ref vscode-extensions
openai.chatgpt
#+end_src
*** OpenCode
Just in case the internet fails, we want to have a OSS coding tool that can wield local models. Enter https://opencode.ai/!
#+begin_src nix :noweb-ref homebrew-taps :noweb yes
"anomalyco/tap"
#+end_src
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"anomalyco/tap/opencode"
#+end_src
*** Ollama
[[https://github.com/ollama/ollama][Ollama]] is a convenient CLI tool to spin up LLMs locally for inference anad and to spawn local APIs that can be used with locally running tools. This should come in handy for offline LLM access and the general development of LLM-powered builds... even when the internet is down or when flying.
**** COMMENT Install Ollama through homebrew
On MacOS, we install Ollama using the [[https://formulae.brew.sh/formula/ollama][brew]]:
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"ollama"
#+end_src
**** Install Ollama from nix packages
We still need to clean up my config to reuse the old dev.nix:
#+begin_src nix :noweb-ref dev-packages
pkgs.ollama
#+end_src
**** Recommended models for offline use
Reference picks for this machine — written down so I don't have to re-research this every time the internet goes sideways. Deeper rationale, benchmarks, and trade-offs live in [[https://linear.app/asabina/issue/VID-597/pick-local-llms-for-offline-work][VID-597]].
Target hardware: MacBook Pro 16" M5 Pro, 64 GB unified memory.
***** Prerequisites
- Ollama =>= 0.19= for the MLX backend on Apple Silicon (released March 2026, requires >32 GB unified memory). Verify with =ollama --version=.
- Default usable VRAM is ~48 GB (macOS reserves ~25%). To push it to ~56 GB before loading a >40 GB model, close apps and run:
#+begin_src sh
sudo sysctl iogpu.wired_limit_mb=57344 # reverts on reboot
#+end_src
***** Install set
Pull in priority order. Disk footprint of the full set is ~128 GB; typically only one or two are loaded at a time.
#+begin_src sh
# 1. Daily driver: coder + agent. ALWAYS LOADED.
# 30.5B total / 3.3B active MoE, 256k context. Fast despite the size.
ollama pull qwen3-coder:30b-a3b-q4_K_M # ~19 GB
# 1b. Agentic coding alternative (released 2026-04-16, Apache 2.0).
# 35B/3B MoE, same efficiency class as #1. Stronger on repo-level and frontend
# workflows. Run alongside #1 for a week; drop whichever underperforms on real tasks.
# If one has to go later, qwen3:32b is the more likely cut.
ollama pull qwen3.6:35b-a3b-q4_K_M # ~24 GB
# 2. Reasoning workhorse (DeepSeek-R1 distilled into Qwen2.5-32B base)
ollama pull deepseek-r1:32b # ~20 GB
# 3. Stretch coder for hard problems (load on demand only).
# 80B/3B MoE, frontier-tier SWE-Bench scores. Verify exact tag with:
# ollama search qwen3-coder
ollama pull qwen3-coder:80b-a3b-q4_K_M # ~45 GB, needs sysctl bump
# 4. Small fast generalist for shell helpers, autocomplete, quick Q&A
ollama pull qwen3:8b # ~5 GB
# 5. (Optional) Best-in-class tool-calling generalist (#2 on BFCL v3, 75.7%)
ollama pull qwen3:32b # ~20 GB
#+end_src
***** Why these picks
| Need | Pick | Notes |
|-----------------------+-----------------------------------------------------+------------------------------------------------------------------------------------------------|
| Coding (daily) | =qwen3-coder:30b-a3b-q4_K_M= | MoE → 30B-quality at 3B-speed. 256k context. Strong SWE-Bench scores. |
| Agentic coding | =qwen3.6:35b-a3b-q4_K_M= | Released 2026-04-16. Same efficiency class, stronger on repo-level + frontend workflows. |
| Coding (hard) | =qwen3-coder:80b-a3b-q4_K_M= | SWE-Bench Verified ~70% (Feb 2026 release). |
| Reasoning | =deepseek-r1:32b= | R1-Distill-Qwen-32B. Best reasoning-per-GB locally. |
| Reasoning (max) | =deepseek-r1:70b= /(optional)/ | ~40 GB Q4. Skip unless 32B feels short. |
| Tool calling / agents | =qwen3:32b= /or/ =qwen3-coder:30b-a3b= | Qwen3-32B is BFCL v3 #2 (75.7%). Coder also handles tool calls well. |
| Generalist (fast) | =qwen3:8b= | Cheap to keep resident. |
Models that *don't* fit on 64 GB and shouldn't be attempted: Qwen3-Coder-480B-A35B (~250 GB), DeepSeek-V3.x / R1 full (671B), GLM-4.5 full (~355B). GLM-4.5-Air /might/ fit at Q4 (~50–55 GB) but is uncomfortably tight — defer.
***** MoE memory math (the gotcha)
For Mixture-of-Experts models, *total* parameters live in RAM, but only *active* parameters drive throughput. So Qwen3-Coder-80B-A3B is "80B in RAM, 3B-speed inference" — that's the entire reason it's worth the footprint on this machine.
***** Engine choice
- *Default to ollama.* Since 0.19 (March 2026) it uses MLX on Apple Silicon, so the historical "ollama is slow" trade-off is largely gone.
- Reach for raw =mlx-lm= / LM Studio only when benchmarking or hosting a single high-throughput inference endpoint (~130 tok/s vs ~71 for llama.cpp on large models).
- Stay on GGUF/ollama for anything talking the OpenAI API, Continue.dev, agent integrations, or juggling multiple models.
**** Auto-start the daemon via launchd
Manual =ollama serve= is how we end up with a stale 0.15.6 daemon still running 6 days after a =darwin-rebuild switch= — the binary on PATH gets upgraded but the long-lived process keeps holding a file descriptor to the old store path. We can't trust ourselves to remember; let nix-darwin own the daemon's lifecycle.
This block tangles into =configuration-darwin.nix= via the =nix-darwin= noweb-ref:
#+begin_src nix :noweb-ref nix-darwin
launchd.user.agents.ollama = {
serviceConfig = {
ProgramArguments = [
"${pkgs.ollama}/bin/ollama"
"serve"
];
# Start at login, restart on any exit
RunAtLoad = true;
KeepAlive = true;
# Headless daemon, not a foreground app
ProcessType = "Background";
# Logs land here; truncate manually if they grow
StandardOutPath = "/Users/${username}/Library/Logs/ollama.stdout.log";
StandardErrorPath = "/Users/${username}/Library/Logs/ollama.stderr.log";
};
# launchd's default PATH is /usr/bin:/bin:/usr/sbin:/sbin which is too narrow
path = [
config.environment.systemPath
];
};
#+end_src
After the next =make nix-darwin-switch=:
#+begin_src sh
# launchd starts the new daemon, but the stale 0.15.6 one is still bound to :11434.
# Kill it once; KeepAlive will respawn the new 0.20.7 binary instantly.
pkill -f "ollama serve"
# Verify
launchctl list | grep ollama # expect: org.nixos.ollama loaded
curl -s localhost:11434/api/version # expect: {"version":"0.20.7"} (or newer)
ollama --version # client and server should match
#+end_src
Logs are at =~/Library/Logs/ollama.{stdout,stderr}.log=. After this point, =ollama serve= should never need to be typed again — every reboot, login, or crash is handled by launchd.
*** llama.cpp
See https://github.com/ggml-org/llama.cpp
#+begin_src nix :noweb-ref dev-packages
pkgs.llama-cpp
#+end_src
*** Pi (coding agent)
#+begin_src nix :noweb-ref homebrew-brews :noweb yes
"pi-coding-agent"
#+end_src
*** COMMENT LM Studio
#+begin_comment
⚠️ Keep in mind that LM Studio isn't FLOSS afaik and it won't run on an Intel MacOS, which makes sense but breaks this conf on my older MacBook Pro.
#+end_comment
With [[https://lmstudio.ai/][LM Studio]], one can easily inference against LLMs, spin up an API to allow other tools to access locally-served LLMs and compute embeddings locally... all through a convenient GUI.
On MacOS, we install LM Studio using the [[https://formulae.brew.sh/cask/lm-studio][cask]]:
#+begin_src nix :noweb-ref homebrew-casks :noweb yes
"lm-studio"
#+end_src
*** Perplexity
#+begin_quote org
[!WARNING]
For all apps installed through Apple App Store, remember to once "Get" the app first through the Apple App Store application in order to make it programmatically installable.
#+end_quote
Perplexity can be found in the [[https://apps.apple.com/de/app/perplexity-ask-anything/id6714467650?l=en-GB&mt=12][Apple App Store]] and may need some manual updates as I'm doing at <2025-05-19 Mon> since it apparently isn't done automatically.
#+begin_src nix :noweb-ref homebrew-masapps :noweb yes
"Perplexity" = 6714467650;
#+end_src
** TODO [5/21] Convert home-manager config to literate config
Refer to [[file:emacs/README.org]] for an example of a literate config that tangles into multiple output files.
- [X] configuration-darwin.nix
- [ ] system/darwin.nix
- [-] direnv
- [ ] .xsession
- [ ] .Xresources.d
- [ ] .Xmodmap
- [ ] tmux
- [X] Neovim
- [ ] Termite
- [ ] Starship
- [X] Rofi (handled through Pywal since [2023-07-03 Mon])
- [ ] Redshift (or Gammastep)
- [ ] Ghorg
- [-] Asciinema
- [ ] Compton
- [ ] Octave
- [ ] Lein
- [ ] Colorit
- [ ] Conky
- [X] Emacs
- [X] Git
** TODO Add MIME types
#+begin_src conf
application/pdf=org.pwmt.zathura-pdf-mupdf.desktop;okularApplication_pdf.desktop;
application/octet-stream=emacsclient.desktop;
#+end_src
* Local Variables
For convenience, we call =delete-trailing-whitespace= as outlined in an [[https://www.mail-archive.com/emacs-orgmode@gnu.org/msg112517.html][emacs-orgmode mailing thread]] to automatically clean up trailing whitespaces that may be artifact from tangling noweb refs that
1. contain line-breaks and are being indented or
2. have no noweb-ref writes
;;; Local Variables:
;;; eval: (add-hook 'org-babel-post-tangle-hook #'delete-trailing-whitespace)
;;; eval: (add-hook 'org-babel-post-tangle-hook #'save-buffer :append)
;;; End: