Mess #
First I’m going to address an elephant in the room:
Why aren’t you publishing your dotfiles?
They’re too much of a mess with a bunch personal data entwined in the commit history that I don’t feel comfortable publicly throwing onto the internet.
Nix snippets #
It’s no secret that I’ve picked up NixOS a few years ago. To that end, there are a few things that I don’t think I’ve seen other people do that I would like to share here.
home-manager
color scheme #
Some time ago, I came across the
nix-colors project and came to the
conclusion that it didn’t fit my needs. As a result, I put/hacked a function
together that extracts the color schemes from
pkgs.kitty-themes
.
I won’t go into the integration details in my personal config as it’s not
exactly something I would call ergonomic. However, this is the function I came
up with:
Expand to see a rather lengthy nix expression
{ lib, config, pkgs, ... }:
arg:
with lib;
let cfg = config.colorscheme;
getKittyTheme = with builtins; (theme:
let matching = filter (x: x.name == theme)
(fromJSON
(readFile
"${pkgs.kitty-themes}/share/kitty-themes/themes.json"));
in throwIf (length matching == 0)
"kitty-themes does not contain a theme named ${theme}"
"${pkgs.kitty-themes}/share/kitty-themes/${(head matching).file}");
unwrapKittyTheme = with pkgs; path: let
theme = runCommand "theme.toml" { nativebuildinputs = [ coreutils ]; } ''
cat '${path}' | sed -E '/^#|^$/d;s/\s+(.*)/ = "\1"/g' > $out
'';
in (builtins.fromTOML (builtins.readFile theme));
defaultTheme = {
selection_foreground = "";
selection_background = "";
foreground = "";
background = "";
color0 = "";
color1 = "";
color2 = "";
color3 = "";
color4 = "";
color5 = "";
color6 = "";
color7 = "";
color8 = "";
color9 = "";
color10 = "";
color11 = "";
color12 = "";
color13 = "";
color14 = "";
color15 = "";
cursor = "";
cursor_text_color = "";
url_color = "";
};
in defaultTheme // unwrapKittyTheme (getKittyTheme arg)
This function takes a name and matches that against the contents of
pkgs.kitty-themes
. If it fails to find something, it throws an error; If does
find something, it returns that file, converts that to something approach TOML
syntax, which is then parsed using builtins.fromTOML
and merged with a
minimum-viable-colorscheme, ensuring all colors are at the least declared as an
empty string; I ran into issues here when using this output in combination with
Qutebrowser when referring to colors that didn’t exist in certain colorschemes.
Qutebrowser #
I manage my Qutebrowser config using the home-manager
module (obviously). In
my Qutebrowser config, I have JavaScript disabled by default and use a list of
exception for trusted sites. When I first tried to set this up, I bumped into
the obvious problem that Nix doesn’t allow you to bind multiple values to a
single name. Luckily, the Qutebrowser module has an extraConfig
option which
takes a string. At first I had a bunch of lines for those exceptions:
config.set('content.javascript.enabled', True, 'https://hoogle.haskell.org/*')
config.set('content.javascript.enabled', True, 'https://search.nixos.org/*')
config.set('content.javascript.enabled', True, 'https://nix.dev/*')
config.set('content.javascript.enabled', True, 'https://voidcruiser.nl/searx/*')
However, I quickly got sick of the inherent inefficiency and illegibility of this approach, so I wrote a few little functions:
...
programs.qutebrowser.extraConfig = let
enableJS = url: "config.set('content.javascript.enabled', True, '${url}')";
javaScriptExceptions = [
"https://hoogle.haskell.org/*"
"https://search.nixos.org/*"
"https://nix.dev/*"
"https://voidcruiser.nl/searx/*"
];
in ''
${with builtins; concatStringSep "\n" (map enableJS javaScriptExceptions)}
# things I haven't managed to abstract properly yet
'';
...
This takes the contents supplied in javaScriptExceptions
and generates a
viable config line based on each item by mapping over it with the enableJS
function. Since the Qutebrowser config syntax can’t read the nix list syntax,
the items of the resulting list and than concatenated using \n
or a newline
character.
XMonad #
My XMonad configuration has a bunch of weird shit in it, some of which I’m proud of, some of which still has bugs that I keep telling myself I will get to At Some Pointâ„¢. Here are some of the nicer bits.
Volume control using scroll wheel #
I have bound Super + scroll {up,down}
bound to {increase,decrease} volume
respectively.
...
, ((modMask, button4), \_ -> safeSpawn "pulsemixer" ["--change-volume","+1"])
, ((modMask, button5), \_ -> safeSpawn "pulsemixer" ["--change-volume","-1"])
, ((modMask .|. shiftMask, button4), \_ -> safeSpawn "pulsemixer" ["--change-volume","+5"])
, ((modMask .|. shiftMask, button5), \_ -> safeSpawn "pulsemixer" ["--change-volume","-5"])
...
The hard part here was coming to the realisation that using a lambda that discards its argument was the best way to handle interactions while satisfying the type signature.
Other than that, these functions are quite straightforward. button4
is ‘scroll
up’ while button5
is ‘scroll down’. I don’t recall where I found this, but it
was somewhere in the documentation. As a result, when XMonad registers a
combination of modMask
and either of the scroll directions, it uses
pulsemixer
to increase or decrease the volume.
Kitty wrappers #
I use the Kitty terminal. Kitty has a huge
feature list, of which I feel like I use about 20% at most. One of these
features is the ability to override config options using the -o
parameter.
This allows you to set a different font(size) or colorscheme or what have you.
I wanted to be able to start a BQN
repl with the BQN386 font right from my
window manager. So I wrote a few functions that take various arguments and
supply them to Kitty without excessive syntax.
The simplest one of these is kittyWithOverrides
. It can only take a list of
-o
parameters.
kittyWithOverrides :: [String] -> X ()
kittyWithOverrides = spawn . ("kitty " ++) . (unwords . map ("-o " ++))
Here is how I use this function to create a BQN
repl window function:
largeTextBQN shell = [ "font_size=17"
, "font_family='BQN386 Unicode'"
, "shell='" ++ shell ++ "'"
]
bqn = kittyWithOverrides $ largeTextBQN "bqn"
Note: I use a largeTextBQN
function rather than a where
binding, because I
use the same settings for a few other repls as well.
This string will evaluate to the following at compile time:
kitty -o font_size=17 -o font_family='BQN386 Unicode' -o shell='/nix/store/6xwwmv4ljbfckkyklh512zxy6l9s0wv4-cbqn-standalone-0.4.0/bin/bqn'
…which will then be fed to spawn
, thereby executing it. If I were to spend
more time on it, I could figure out a way to do this properly using safeSpawn
or one of its variants, but as it stands, I’m too lazy to do so.
For a more general interface I wrote a kittyWithParams
function:
kittyWithParams :: [(String,String)] -> X ()
kittyWithParams = spawn . ("kitty " ++) . unwords . map unwrapParams
where unwrapParams (flag,parameter) = case last flag of
'=' -> flag ++ parameter
_ -> flag ++ " " ++ parameter
Comparatively, it is rather messy. Still, the basic functionality is there and I’m quite happy with how it works.