Modularize config

This commit is contained in:
Henrik Lissner 2020-03-29 01:48:43 -04:00
parent 67da3cf844
commit 592ee79a83
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
92 changed files with 2138 additions and 1141 deletions

View file

@ -6,7 +6,7 @@ device:
networking.hostName = lib.mkDefault device; networking.hostName = lib.mkDefault device;
imports = [ imports = [
./options.nix ./modules
"${./hosts}/${device}" "${./hosts}/${device}"
]; ];
@ -16,15 +16,15 @@ device:
# So we can use absolute import paths # So we can use absolute import paths
"bin=/etc/dotfiles/bin" "bin=/etc/dotfiles/bin"
"config=/etc/dotfiles/config" "config=/etc/dotfiles/config"
"modules=/etc/dotfiles/modules"
]; ];
# ...but we still need to set nixpkgs.overlays to make them visible to the # Add custom packages & unstable channel, so they can be accessed via pkgs.*
# rebuild process, however...
nixpkgs.overlays = import ./overlays.nix; nixpkgs.overlays = import ./overlays.nix;
nixpkgs.config.allowUnfree = true; # forgive me Stallman senpai nixpkgs.config.allowUnfree = true; # forgive me Stallman senpai
# For instant nix-shell scripts environment.systemPackages = with pkgs; [
environment.systemPackages = [ pkgs.my.cached-nix-shell ]; gnumake # for our own makefile
my.cached-nix-shell # for instant nix-shell scripts
];
environment.shellAliases = { environment.shellAliases = {
nix-env = "NIXPKGS_ALLOW_UNFREE=1 nix-env"; nix-env = "NIXPKGS_ALLOW_UNFREE=1 nix-env";
nix-shell = ''NIX_PATH="nixpkgs-overlays=/etc/dotfiles/overlays.nix:$NIX_PATH" nix-shell''; nix-shell = ''NIX_PATH="nixpkgs-overlays=/etc/dotfiles/overlays.nix:$NIX_PATH" nix-shell'';

View file

@ -5,16 +5,16 @@
imports = [ imports = [
../personal.nix # common settings ../personal.nix # common settings
./hardware-configuration.nix ./hardware-configuration.nix
## Apps
<modules/shell/zsh.nix>
## Services
<modules/services/ssh.nix>
# <modules/services/plex.nix>
<modules/services/jellyfin.nix>
<modules/services/syncthing.nix>
<modules/services/calibre-server.nix>
]; ];
modules = {
shell.zsh.enable = true;
services.calibre.enable = true;
services.jellyfin.enable = true;
services.ssh.enable = true;
services.syncthing.enable = true;
};
my.zsh.rc = lib.readFile <modules/themes/aquanaut/zsh/prompt.zsh>; my.zsh.rc = lib.readFile <modules/themes/aquanaut/zsh/prompt.zsh>;
networking.networkmanager.enable = true; networking.networkmanager.enable = true;

View file

@ -5,16 +5,17 @@
imports = [ imports = [
../personal.nix ../personal.nix
./hardware-configuration.nix ./hardware-configuration.nix
## Apps
<modules/shell/git.nix>
<modules/shell/zsh.nix>
## Services
<modules/services/ssh.nix>
<modules/services/nginx.nix>
<modules/services/gitea.nix>
<modules/services/syncthing.nix>
]; ];
modules = {
shell.git.enable = true;
shell.zsh.enable = true;
services.ssh.enable = true;
services.nginx.enable = true;
services.gitea.enable = true;
services.syncthing.enable = true;
};
my.zsh.rc = lib.readFile <modules/themes/aquanaut/zsh/prompt.zsh>; my.zsh.rc = lib.readFile <modules/themes/aquanaut/zsh/prompt.zsh>;
networking.networkmanager.enable = true; networking.networkmanager.enable = true;

View file

@ -1,4 +1,4 @@
# hosts/default.nix --- settings common to all my systems # hosts/common.nix --- settings common to all my systems
{ pkgs, ... }: { pkgs, ... }:
{ {
@ -13,7 +13,6 @@
sshfs sshfs
]; ];
### My user settings ### My user settings
my.username = "hlissner"; my.username = "hlissner";
my.user = { my.user = {

View file

@ -1,41 +1,73 @@
# Kuro -- my desktop # Kuro -- my desktop
{ pkgs, ... }: { pkgs, options, config, ... }:
{ {
imports = [ imports = [
../personal.nix # common settings ../personal.nix # common settings
./hardware-configuration.nix ./hardware-configuration.nix
## Desktop/shell environment
<modules/desktop/bspwm.nix>
# <modules/desktop/stumpwm.nix>
## Apps
<modules/browser/firefox.nix>
<modules/dev/cc.nix>
<modules/dev/rust.nix>
# <modules/dev/common-lisp.nix>
<modules/editors/emacs.nix>
<modules/editors/vim.nix>
<modules/gaming/steam.nix>
<modules/shell/direnv.nix>
<modules/shell/git.nix>
<modules/shell/gnupg.nix>
<modules/shell/pass.nix>
<modules/shell/tmux.nix>
<modules/shell/ranger.nix>
<modules/shell/zsh.nix>
## Project-based
<modules/chat.nix> # discord, mainly
<modules/recording.nix> # recording video & audio
<modules/daw.nix> # making music
<modules/music.nix> # playing music
<modules/graphics.nix> # art & design
<modules/vm.nix> # virtualbox for testing
## Services
<modules/services/syncthing.nix>
## Theme
<modules/themes/fluorescence>
]; ];
modules = {
desktop = {
bspwm.enable = true;
apps.rofi.enable = true;
apps.discord.enable = true;
# apps.skype.enable = true;
apps.daw.enable = true; # making music
apps.graphics.enable = true; # raster/vector/sprites
apps.recording.enable = true; # recording screen/audio
apps.vm.enable = true; # virtualbox for testing
term.default = "xst";
term.st.enable = true;
browsers.default = "firefox";
browsers.firefox.enable = true;
# browsers.qutebrowser.enable = true;
# gaming.emulators.psx.enable = true;
# gaming.steam.enable = true;
# gaming.factorio.enable = true;
};
editors = {
default = "nvim";
emacs.enable = true;
vim.enable = true;
};
dev = {
cc.enable = true;
common-lisp.enable = true;
rust.enable = true;
scala.enable = true;
};
media = {
mpv.enable = true;
spotify.enable = true;
};
shell = {
direnv.enable = true;
git.enable = true;
gnupg.enable = true;
# weechat.enable = true;
pass.enable = true;
tmux.enable = true;
ranger.enable = true;
zsh.enable = true;
};
services = {
syncthing.enable = true;
};
# themes.aquanaut.enable = true;
themes.fluorescence.enable = true;
};
networking.networkmanager.enable = true; networking.networkmanager.enable = true;
time.timeZone = "America/Toronto"; time.timeZone = "America/Toronto";
} }

View file

@ -33,7 +33,7 @@
with pkgs; [ inetutils mtr sysstat git ]; with pkgs; [ inetutils mtr sysstat git ];
imports = [ imports = [
./. ./common.nix
<modules/editors/vim.nix> <modules/editors/vim.nix>
<modules/shell/git.nix> <modules/shell/git.nix>
<modules/shell/zsh.nix> <modules/shell/zsh.nix>

View file

@ -2,7 +2,7 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
{ {
imports = [ ./. ]; imports = [ ./common.nix ];
# Support for more filesystems # Support for more filesystems
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [

View file

@ -5,32 +5,68 @@
imports = [ imports = [
../personal.nix # common settings ../personal.nix # common settings
./hardware-configuration.nix ./hardware-configuration.nix
## Dekstop environment
<modules/desktop/bspwm.nix>
## Apps
<modules/browser/firefox.nix>
<modules/dev>
<modules/editors/emacs.nix>
<modules/editors/vim.nix>
<modules/shell/direnv.nix>
<modules/shell/git.nix>
<modules/shell/gnupg.nix>
<modules/shell/pass.nix>
<modules/shell/tmux.nix>
<modules/shell/zsh.nix>
## Project-based
<modules/chat.nix> # discord, mainly
<modules/recording.nix> # recording video & audio
<modules/daw.nix> # making music
<modules/music.nix> # playing music
<modules/graphics.nix> # art & design
# <modules/vm.nix> # virtualbox for testing
## Services
<modules/services/syncthing.nix>
## Theme
<modules/themes/aquanaut>
]; ];
modules = {
desktop = {
bspwm.enable = true;
apps.rofi.enable = true;
apps.discord.enable = true;
# apps.skype.enable = true;
apps.daw.enable = true; # making music
apps.graphics.enable = true; # raster/vector/sprites
apps.recording.enable = true; # recording screen/audio
# apps.vm.enable = true; # virtualbox for testing
term.default = "xst";
term.st.enable = true;
browsers.default = "firefox";
browsers.firefox.enable = true;
# browsers.qutebrowser.enable = true;
# gaming.emulators.psx.enable = true;
# gaming.steam.enable = true;
# gaming.factorio.enable = true;
};
editors = {
default = "nvim";
emacs.enable = true;
vim.enable = true;
};
# dev = {
# cc.enable = true;
# # common-lisp.enable = true;
# rust.enable = true;
# };
media = {
mpv.enable = true;
spotify.enable = true;
};
shell = {
direnv.enable = true;
git.enable = true;
gnupg.enable = true;
# weechat.enable = true;
pass.enable = true;
tmux.enable = true;
ranger.enable = true;
zsh.enable = true;
};
services = {
syncthing.enable = true;
};
# themes.aquanaut.enable = true;
themes.fluorescence.enable = true;
};
networking.wireless.enable = true; networking.wireless.enable = true;
hardware.opengl.enable = true; hardware.opengl.enable = true;

View file

@ -1,26 +0,0 @@
# modules/browser/firefox.nix --- https://www.mozilla.org/en-US/firefox
#
# Oh firefox, gateway to the interwebs, devourer of ram. Give onto me your
# infinite knowledge and shelter me from ads.
{ config, lib, pkgs, ... }:
{
my.packages = with pkgs; [
firefox-bin
(pkgs.writeScriptBin "firefox-private" ''
#!${stdenv.shell}
${firefox}/bin/firefox --private-window "$@"
'')
(makeDesktopItem {
name = "firefox-private";
desktopName = "Firefox (Private)";
genericName = "Open a private Firefox window";
icon = "firefox";
exec = "${firefox-bin}/bin/firefox --private-window";
categories = "Network";
})
];
my.env.BROWSER = "firefox";
my.env.XDG_DESKTOP_DIR = "$HOME"; # prevent firefox creating ~/Desktop
}

View file

@ -1,51 +0,0 @@
# modules/browser/qutebrowser.nix --- https://github.com/qutebrowser/qutebrowser
#
# Qutebrowser is cute because it's not enough of a browser to be handsome.
# Still, we can all tell he'll grow up to be one hell of a lady-killer.
{ config, lib, pkgs, ... }:
{
my.packages = with pkgs; [
qutebrowser
(pkgs.writeScriptBin "qutebrowser-private" ''
#!${stdenv.shell}
${qutebrowser}/bin/qutebrowser ":open -p $@"
'')
(makeDesktopItem {
name = "qutebrowser-private";
desktopName = "Qutebrowser (Private)";
genericName = "Open a private Qutebrowser window";
icon = "qutebrowser";
exec = "${qutebrowser}/bin/qutebrowser ':open -p'";
categories = "Network";
})
];
my.env.BROWSER = "qutebrowser";
my.home.xdg = {
configFile."qutebrowser" = {
source = <config/qutebrowser>;
recursive = true;
};
dataFile = {
"qutebrowser/greasemonkey" = {
source = <config/qutebrowser/greasemonkey>;
recursive = true;
};
"qutebrowser/userstyles.css".source =
let compiledStyles =
with pkgs; runCommand "compileUserStyles"
{ buildInputs = [ sass ]; } ''
mkdir "$out"
for file in ${<config/qutebrowser/styles>}/*.scss; do
scss --sourcemap=none \
--no-cache \
--style compressed \
--default-encoding utf-8 \
"$file" \
>>"$out/userstyles.css"
done
'';
in "${compiledStyles}/userstyles.css";
};
};
}

View file

@ -1,21 +0,0 @@
{ config, lib, pkgs, ... }:
{
my.packages = with pkgs; [
vivaldi
vivaldi-widevine
(pkgs.writeScriptBin "vivaldi-private" ''
#!${stdenv.shell}
${vivaldi}/bin/vivaldi --incognito "$@"
'')
(makeDesktopItem {
name = "vivaldi-private";
desktopName = "Vivaldi (Incognito)";
genericName = "Open an incognito Vivaldi window";
icon = "vivaldi";
exec = "${vivaldi}/bin/vivaldi --incognito";
categories = "Network";
})
];
my.env.BROWSER = "vivaldi";
}

View file

@ -1,12 +0,0 @@
# modules/chat.nix
#
# Even neckbeards have a social life. Not that I have one. A neckbeard, I mean.
# But when I do have either, then discord and weechat are my go-to.
{ pkgs, ... }:
{
my.packages = with pkgs; [
# weechat # TODO For the real neckbeards
discord # For everyone else
];
}

View file

@ -1,18 +0,0 @@
# modules/music.nix
#
# I make music for my games. LMMS is my DAW; or will be, once I've weened myself
# off of Fruityloops. When I'm in the mood for a quicky I fire up sunvox
# instead. It runs absolutely anywhere, even on my ipad and phone. As if I'd
# ever need to.
{ config, lib, pkgs, ... }:
{
my.packages = with pkgs; [
audacity # for recording and remastering audio
sunvox # for making music (where LMMS is overkill)
# lmms on stable is broken due to 'Could not find the Qt platform plugin
# "xcb" in ""' error: https://github.com/NixOS/nixpkgs/issues/76074
unstable.lmms # for making music
];
}

101
modules/default.nix Normal file
View file

@ -0,0 +1,101 @@
{ config, options, lib, ... }:
with lib;
let mkOptionStr = value: mkOption
{ type = types.str;
default = value; };
in {
imports = [
<home-manager/nixos>
./desktop
./dev
./editors
./media
./services
./shell
./themes
];
options = {
my = {
## Personal details
username = mkOptionStr "hlissner";
email = mkOptionStr "henrik@lissner.net";
## Convenience aliases
home = mkOption { type = options.home-manager.users.type.functor.wrapped; };
user = mkOption { type = types.submodule; };
packages = mkOption { type = with types; listOf package; };
## Environment
env = mkOption {
type = with types; attrsOf (either (either str path) (listOf (either str path)));
apply = mapAttrs
(n: v: if isList v
then concatMapStringsSep ":" (x: toString x) v
else (toString v));
};
init = mkOption {
type = types.lines;
description = ''
An init script that runs after the environment has been rebuilt or
booted. Anything done here should be idempotent and inexpensive.
'';
};
alias = mkOption {
type = with types; nullOr (attrsOf (nullOr (either str path)));
};
zsh = {
rc = mkOption {
type = types.lines;
default = "";
description = ''
Zsh lines to be written to $XDG_CONFIG_HOME/zsh/extra.zshrc and
sourced by $XDG_CONFIG_HOME/zsh/.zshrc
'';
};
env = mkOption {
type = types.lines;
default = "";
description = ''
Zsh lines to be written to $XDG_CONFIG_HOME/zsh/extra.zshenv and
sourced by $XDG_CONFIG_HOME/zsh/.zshenv
'';
};
};
};
};
config = {
## Convenience aliases
home-manager.users.${config.my.username} = mkAliasDefinitions options.my.home;
users.users.${config.my.username} = mkAliasDefinitions options.my.user;
my.user.packages = config.my.packages;
## PATH should always start with its old value
my.env.PATH = [ <bin> "$PATH" ];
environment.extraInit =
let exportLines = mapAttrsToList (n: v: "export ${n}=\"${v}\"") config.my.env;
in ''
${concatStringsSep "\n" exportLines}
${config.my.init}
'';
# I avoid programs.zsh.*Init variables because they initialize too soon. My
# zsh config is particular about load order.
my.home.xdg.configFile = {
"zsh/extra.zshrc".text =
let aliasLines = mapAttrsToList (n: v: "alias ${n}=\"${v}\"") config.my.alias;
in ''
# This file is autogenerated, do not edit it!
${concatStringsSep "\n" aliasLines}
${config.my.zsh.rc}
'';
"zsh/extra.zshenv".text = ''
# This file is autogenerated, do not edit it!
${config.my.zsh.env};
'';
};
};
}

View file

@ -0,0 +1,28 @@
# modules/desktop/apps/daw.nix
#
# I make music for my games. LMMS is my DAW; or will be, once I've weened myself
# off of Fruityloops. When I'm in the mood for a quicky I fire up sunvox
# instead. It runs absolutely anywhere, even on my ipad and phone. As if I'd
# ever need to.
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.desktop.apps.daw = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.desktop.apps.daw.enable {
my.packages = with pkgs; [
# lmms on stable is broken due to 'Could not find the Qt platform plugin
# "xcb" in ""' error: https://github.com/NixOS/nixpkgs/issues/76074
unstable.lmms # for making music
audacity # for recording and remastering audio
# sunvox # for making music (where LMMS is overkill)
];
};
}

View file

@ -0,0 +1,13 @@
{ config, lib, pkgs, ... }:
{
imports = [
./daw.nix
./discord.nix
./graphics.nix
./recording.nix
./rofi.nix
./skype.nix
./vm.nix
];
}

View file

@ -0,0 +1,17 @@
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.desktop.apps.discord = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.desktop.apps.discord.enable {
my.packages = with pkgs; [
discord
# ripcord
];
};
}

View file

@ -0,0 +1,50 @@
# modules/desktop/apps/graphics.nix
#
# The hardest part about switching to linux? Sacrificing Adobe. It really is
# difficult to replace and its open source alternatives don't *quite* cut it,
# but enough that I can do a fraction of it on Linux. For the rest I have a
# second computer dedicated to design work (and gaming).
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.desktop.apps.graphics =
let mkBoolDefault = bool: mkOption {
type = types.bool;
default = bool;
};
in {
enable = mkBoolDefault false;
tools.enable = mkBoolDefault false;
raster.enable = mkBoolDefault false;
vector.enable = mkBoolDefault false;
sprites.enable = mkBoolDefault false;
};
config = let gfx = config.modules.desktop.apps.graphics; in {
my.packages = with pkgs;
(if gfx.enable || gfx.tools.enable then [
font-manager # so many damned fonts...
imagemagick # for image manipulation from the shell
] else []) ++
# replaces illustrator & indesign
(if gfx.enable || gfx.vector.enable then [
inkscape
] else []) ++
# Replaces photoshop
(if gfx.enable || gfx.raster.enable then [
krita
gimp
gimpPlugins.resynthesizer2 # content-aware scaling in gimp
] else []) ++
# Sprite sheets & animation
(if gfx.enable || gfx.sprites.enable then [ aseprite-unfree ] else []);
my.home.xdg.configFile = mkIf (gfx.enable || gfx.raster.enable) {
"GIMP/2.10" = { source = <config/gimp>; recursive = true; };
};
};
}

View file

@ -0,0 +1,28 @@
# modules/desktop/apps/recording.nix
#
# OBS to capture footage/stream, DaVinci Resolve for editing (on my Windows
# system -- it will run on linux, but it can't be automated on nix, what with
# their devs registration-gating their free download).
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.desktop.apps.recording =
let mkBoolDefault = bool: mkOption {
type = types.bool;
default = bool;
};
in {
enable = mkBoolDefault false;
audio.enable = mkBoolDefault false;
video.enable = mkBoolDefault false;
};
config = let rc = config.modules.desktop.apps.recording; in {
my.packages = with pkgs;
# for recording and remastering audio
(if rc.enable || rc.audio.enable then [ audacity ] else []) ++
# for longer term streaming/recording the screen
(if rc.enable || rc.video.enable then [ obs-studio handbrake ] else []);
};
}

View file

@ -1,15 +0,0 @@
# modules/desktop/apps/redshift.nix
{ config, lib, pkgs, ... }:
{
services.redshift.enable = true;
# For redshift
location = (if config.time.timeZone == "America/Toronto" then {
latitude = 43.70011;
longitude = -79.4163;
} else if config.time.timeZone == "Europe/Copenhagen" then {
latitude = 55.88;
longitude = 12.5;
} else {});
}

View file

@ -1,6 +1,15 @@
{ config, lib, pkgs, ... }: { config, options, lib, pkgs, ... }:
with lib;
{ {
options.modules.desktop.apps.rofi = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.desktop.apps.rofi.enable {
my = { my = {
# link recursively so other modules can link files in its folder # link recursively so other modules can link files in its folder
home.xdg.configFile."rofi" = { home.xdg.configFile."rofi" = {
@ -14,6 +23,17 @@
exec ${rofi}/bin/rofi -terminal xst -m -1 "$@" exec ${rofi}/bin/rofi -terminal xst -m -1 "$@"
'') '')
# For rapidly test changes to rofi's stylesheets
# (writeScriptBin "rofi-test" ''
# #!${stdenv.shell}
# themefile=$1
# themename=${modules.theme.name}
# shift
# exec rofi \
# -theme ~/.dotfiles/modules/themes/$themename/rofi/$themefile \
# "$@"
# '')
# Fake rofi dmenu entries # Fake rofi dmenu entries
(makeDesktopItem { (makeDesktopItem {
name = "rofi-bookmarkmenu"; name = "rofi-bookmarkmenu";
@ -50,14 +70,15 @@
name = "sleep"; name = "sleep";
desktopName = "System: Sleep"; desktopName = "System: Sleep";
icon = "system-suspend"; icon = "system-suspend";
exec = "zzz -f"; exec = "${<bin/zzz>} -f";
}) })
(makeDesktopItem { (makeDesktopItem {
name = "lock-display"; name = "lock-display";
desktopName = "Lock screen"; desktopName = "Lock screen";
icon = "system-lock-screen"; icon = "system-lock-screen";
exec = "zzz"; exec = "${<bin/zzz>}";
}) })
]; ];
}; };
};
} }

View file

@ -0,0 +1,17 @@
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.desktop.apps.skype = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.desktop.apps.skype.enable {
my.packages = with pkgs; [
skypeforlinux
skype_call_recorder
];
};
}

View file

@ -1,18 +0,0 @@
{ config, lib, pkgs, ... }:
{
# xst-256color isn't supported over ssh, so revert to a known one
my.zsh.rc = ''[ "$TERM" = xst-256color ] && export TERM=xterm-256color'';
my.packages = with pkgs; [
xst # st + nice-to-have extensions
(makeDesktopItem {
name = "xst";
desktopName = "Suckless Terminal";
genericName = "Default terminal";
icon = "utilities-terminal";
exec = "${xst}/bin/xst";
categories = "Development;System;Utility";
})
];
}

View file

@ -1,8 +0,0 @@
{ config, lib, pkgs, ... }:
{
my.packages = with pkgs; [
xfce.thunar
xfce.tumbler # for thumbnails
];
}

View file

@ -1,7 +0,0 @@
{ config, lib, pkgs, ... }:
{
my.packages = with pkgs; [
rxvt_unicode
];
}

View file

@ -0,0 +1,25 @@
# modules/desktop/apps/vm.nix
#
# For testing software or building it on other OSes. If I find out how to get
# macOS on qemu/libvirt I'd be happy to leave virtualbox behind.
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.desktop.apps.vm = {
enable = mkOption {
type = types.bool;
default = false;
};
};
# TODO Figure out macOS guest on libvirt/qemu instead
config = mkIf config.modules.desktop.apps.vm.enable {
virtualisation.virtualbox.host = {
enable = true;
enableExtensionPack = true; # urg, takes so long to build
};
my.user.extraGroups = [ "vboxusers" ];
};
}

View file

@ -0,0 +1,20 @@
{ config, lib, pkgs, ... }:
with lib;
{
imports = [
./firefox.nix
./qutebrowser.nix
./vivaldi.nix
];
options.modules.desktop.browsers = {
default = mkOption {
type = with types; nullOr str;
default = null;
};
};
config = mkIf (config.modules.desktop.browsers.default != null) {
my.env.BROWSER = config.modules.desktop.browsers.default;
};
}

View file

@ -0,0 +1,30 @@
# modules/browser/firefox.nix --- https://www.mozilla.org/en-US/firefox
#
# Oh firefox, gateway to the interwebs, devourer of ram. Give onto me your
# infinite knowledge and shelter me from ads.
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.desktop.browsers.firefox = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.desktop.browsers.firefox.enable {
my.packages = with pkgs; [
firefox-bin
(makeDesktopItem {
name = "firefox-private";
desktopName = "Firefox (Private)";
genericName = "Open a private Firefox window";
icon = "firefox";
exec = "${firefox-bin}/bin/firefox --private-window";
categories = "Network";
})
];
my.env.XDG_DESKTOP_DIR = "$HOME"; # (try to) prevent ~/Desktop
};
}

View file

@ -0,0 +1,33 @@
# modules/browser/qutebrowser.nix --- https://github.com/qutebrowser/qutebrowser
#
# Qutebrowser is cute because it's not enough of a browser to be handsome.
# Still, we can all tell he'll grow up to be one hell of a lady-killer.
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.desktop.browsers.qutebrowser = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.desktop.browsers.qutebrowser.enable {
my.packages = with pkgs; [
qutebrowser
(makeDesktopItem {
name = "qutebrowser-private";
desktopName = "Qutebrowser (Private)";
genericName = "Open a private Qutebrowser window";
icon = "qutebrowser";
exec = "${qutebrowser}/bin/qutebrowser ':open -p'";
categories = "Network";
})
];
my.home.xdg.configFile."qutebrowser" = {
source = <config/qutebrowser>;
recursive = true;
};
};
}

View file

@ -0,0 +1,27 @@
# modules/browser/vivaldi.nix --- ...
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.desktop.browsers.vivaldi = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.desktop.browsers.vivaldi.enable {
my.packages = with pkgs; [
vivaldi
vivaldi-widevine
(makeDesktopItem {
name = "vivaldi-private";
desktopName = "Vivaldi (Incognito)";
genericName = "Open an incognito Vivaldi window";
icon = "vivaldi";
exec = "${vivaldi}/bin/vivaldi --incognito";
categories = "Network";
})
];
};
}

View file

@ -1,10 +1,15 @@
{ config, lib, pkgs, ... }: { config, options, lib, pkgs, ... }:
with lib;
{ {
imports = [ imports = [
./. # common settings ./common.nix
]; ];
options.modules.desktop.bspwm = {
enable = mkOption { type = types.bool; default = false; };
};
config = mkIf config.modules.desktop.bspwm.enable {
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
lightdm lightdm
dunst dunst
@ -17,18 +22,22 @@
services = { services = {
compton.enable = true; compton.enable = true;
redshift.enable = true;
xserver = { xserver = {
enable = true;
windowManager.default = "bspwm"; windowManager.default = "bspwm";
windowManager.bspwm.enable = true; windowManager.bspwm = {
enable = true;
configFile = <config/bspwm/bspwmrc>;
sxhkd.configFile = <config/sxhkd/sxhkdrc>;
};
displayManager.lightdm.enable = true; displayManager.lightdm.enable = true;
displayManager.lightdm.greeters.mini.enable = true; displayManager.lightdm.greeters.mini.enable = true;
}; };
}; };
my.home.xdg.configFile = {
"sxhkd".source = <config/sxhkd>;
# link recursively so other modules can link files in their folders # link recursively so other modules can link files in their folders
"bspwm" = { my.home.xdg.configFile."bspwm" = {
source = <config/bspwm>; source = <config/bspwm>;
recursive = true; recursive = true;
}; };

103
modules/desktop/common.nix Normal file
View file

@ -0,0 +1,103 @@
{ config, lib, pkgs, ... }:
{
my.packages = with pkgs; [
# I often need a thumbnail browser to show off, peruse or organize photos,
# design work, or digital art.
xfce.thunar
xfce.tumbler # for thumbnails
calibre # managing my ebooks
evince # pdf reader
feh # image viewer
mpv # video player
xclip
xdotool
libqalculate # calculator cli w/ currency conversion
(makeDesktopItem {
name = "scratch-calc";
desktopName = "Calculator";
icon = "calc";
exec = "scratch '${tmux}/bin/tmux new-session -s calc -n calc qalc'";
categories = "Development";
})
];
## Sound
sound.enable = true;
hardware.pulseaudio.enable = true;
## Fonts
fonts = {
enableFontDir = true;
enableGhostscriptFonts = true;
fonts = with pkgs; [
ubuntu_font_family
dejavu_fonts
fira-code
fira-code-symbols
symbola
noto-fonts
noto-fonts-cjk
font-awesome-ttf
siji
];
fontconfig.defaultFonts = {
sansSerif = ["Ubuntu"];
monospace = ["Fira Code"];
};
};
## Apps/Services
# For redshift
location = (if config.time.timeZone == "America/Toronto" then {
latitude = 43.70011;
longitude = -79.4163;
} else if config.time.timeZone == "Europe/Copenhagen" then {
latitude = 55.88;
longitude = 12.5;
} else {});
services.xserver = {
displayManager.lightdm.greeters.mini.user = config.my.username;
};
services.compton = {
backend = "glx";
vSync = true;
opacityRules = [
# "100:class_g = 'Firefox'"
# "100:class_g = 'Vivaldi-stable'"
"100:class_g = 'VirtualBox Machine'"
# Art/image programs where we need fidelity
"100:class_g = 'Gimp'"
"100:class_g = 'Inkscape'"
"100:class_g = 'aseprite'"
"100:class_g = 'krita'"
"100:class_g = 'feh'"
"100:class_g = 'mpv'"
"100:class_g = 'Rofi'"
"100:class_g = 'Peek'"
"99:_NET_WM_STATE@:32a = '_NET_WM_STATE_FULLSCREEN'"
];
shadowExclude = [
# Put shadows on notifications, the scratch popup and rofi only
"! name~='(rofi|scratch|Dunst)$'"
];
settings.blur-background-exclude = [
"window_type = 'dock'"
"window_type = 'desktop'"
"class_g = 'Rofi'"
"_GTK_FRAME_EXTENTS@:c"
];
};
# Try really hard to get QT to respect my GTK theme.
my.env.GTK_DATA_PREFIX = [ "${config.system.path}" ];
my.env.QT_QPA_PLATFORMTHEME = "gtk2";
qt5 = { style = "gtk2"; platformTheme = "gtk2"; };
services.xserver.displayManager.sessionCommands = ''
export GTK2_RC_FILES="$XDG_CONFIG_HOME/gtk-2.0/gtkrc"
source "$XDG_CONFIG_HOME"/xsession/*.sh
xrdb -merge "$XDG_CONFIG_HOME"/xtheme/*
'';
}

View file

@ -2,96 +2,12 @@
{ {
imports = [ imports = [
## Desktop apps ./bspwm.nix
./apps/redshift.nix # ./stumpwm.nix
./apps/rofi.nix # My launcher
# I often need a thumbnail browser to show off, peruse or organize photos, ./apps
# design work, or digital art. ./term
# ./apps/nautilus.nix ./browsers
./apps/thunar.nix ./gaming
## Terminal
# ./apps/alacritty.nix
./apps/st.nix
# ./apps/urxvt.nix
]; ];
services.xserver = {
enable = true;
desktopManager.xterm.enable = lib.mkDefault false;
displayManager.lightdm.greeters.mini.user = config.my.username;
};
my.packages = with pkgs; [
calibre # managing my ebooks
evince # pdf reader
feh # image viewer
mpv # video player
xclip
xdotool
libqalculate # calculator cli w/ currency conversion
(makeDesktopItem {
name = "scratch-calc";
desktopName = "Calculator";
icon = "calc";
exec = "scratch '${tmux}/bin/tmux new-session -s calc -n calc qalc'";
categories = "Development";
})
];
## Sound
sound.enable = true;
hardware.pulseaudio.enable = true;
## Fonts
fonts = {
enableFontDir = true;
enableGhostscriptFonts = true;
fonts = with pkgs; [
ubuntu_font_family
dejavu_fonts
fira-code
fira-code-symbols
symbola
noto-fonts
noto-fonts-cjk
font-awesome-ttf
siji
];
fontconfig.defaultFonts = {
sansSerif = ["Ubuntu"];
monospace = ["Fira Code"];
};
};
services.compton = {
backend = "glx";
vSync = true;
opacityRules = [
# "100:class_g = 'Firefox'"
# "100:class_g = 'Vivaldi-stable'"
"100:class_g = 'VirtualBox Machine'"
# Art/image programs where we need fidelity
"100:class_g = 'Gimp'"
"100:class_g = 'Inkscape'"
"100:class_g = 'aseprite'"
"100:class_g = 'krita'"
"100:class_g = 'feh'"
"100:class_g = 'mpv'"
"100:class_g = 'Rofi'"
"100:class_g = 'Peek'"
"99:_NET_WM_STATE@:32a = '_NET_WM_STATE_FULLSCREEN'"
];
shadowExclude = [
# Put shadows on notifications, the scratch popup and rofi only
"! name~='(scratch|Dunst)$'"
];
settings.blur-background-exclude = [
"window_type = 'dock'"
"window_type = 'desktop'"
"class_g = 'Rofi'"
"_GTK_FRAME_EXTENTS@:c"
];
};
} }

View file

@ -0,0 +1,9 @@
{ config, lib, pkgs, ... }:
{
imports = [
./emulators.nix
./factorio.nix
./steam.nix
];
}

View file

@ -0,0 +1,27 @@
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.desktop.gaming.emulators =
let mkBoolDefault = bool: mkOption {
type = types.bool;
default = bool;
};
in {
psx.enable = mkBoolDefault false; # Playstation
ds.enable = mkBoolDefault false; # Nintendo DS
gb.enable = mkBoolDefault false; # GameBoy + GameBoy Color
gba.enable = mkBoolDefault false; # GameBoy Advance
snes.enable = mkBoolDefault false; # Super Nintendo
};
config = let emu = config.modules.desktop.gaming.emulators; in {
my.packages = with pkgs;
(if emu.psx.enable then [ epsxe ] else []) ++
(if emu.ds.enable then [ desume ] else []) ++
(if (emu.gba.enable ||
emu.gb.enable ||
emu.snes.enable)
then [ higan ] else []);
};
}

View file

@ -0,0 +1,17 @@
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.desktop.gaming.factorio = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.desktop.gaming.factorio.enable {
my.packages = with pkgs; [
unstable.factorio-experimental
];
};
}

View file

@ -0,0 +1,30 @@
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.desktop.gaming.steam = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.desktop.gaming.steam.enable {
my.packages = with pkgs; [
# Get steam to keep its garbage out of $HOME
(writeScriptBin "steam" ''
#!${stdenv.shell}
HOME="$XDG_DATA_HOME/steamlib" exec ${steam}/bin/steam "$@"
'')
# for GOG and humblebundle games
(writeScriptBin "steam-run" ''
#!${stdenv.shell}
HOME="$XDG_DATA_HOME/steamlib" exec ${steam-run-native}/bin/steam-run "$@"
'')
xboxdrv # driver for 360 controller
];
hardware.opengl.driSupport32Bit = true;
hardware.pulseaudio.support32Bit = true;
};
}

View file

@ -1,10 +1,8 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
# let unstable = import <nixos-unstable> {};
# in
{ {
imports = [ imports = [
./. # common settings ./common.nix
]; ];
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
@ -15,7 +13,9 @@
# unstable.services.picom.enable = true; # unstable.services.picom.enable = true;
services = { services = {
redshift.enable = true;
xserver = { xserver = {
enable = true;
windowManager.default = "stumpwm"; windowManager.default = "stumpwm";
windowManager.stumpwm.enable = true; windowManager.stumpwm.enable = true;
displayManager.lightdm.enable = true; displayManager.lightdm.enable = true;

View file

@ -0,0 +1,23 @@
{ config, options, lib, pkgs, ... }:
with lib;
{
imports = [
# ./alacritty.nix
./st.nix
# ./urxvt.nix
];
options.modules.desktop.term = {
default = mkOption {
type = types.str;
default = "xterm";
};
};
config = {
services.xserver.desktopManager.xterm.enable =
config.modules.desktop.term.default == "xterm";
my.env.TERMINAL = config.modules.editors.default;
};
}

View file

@ -0,0 +1,28 @@
{ config, lib, pkgs, ... }:
with lib;
{
options.modules.desktop.term.st = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.desktop.term.st.enable {
# xst-256color isn't supported over ssh, so revert to a known one
my.zsh.rc = ''[ "$TERM" = xst-256color ] && export TERM=xterm-256color'';
my.packages = with pkgs; [
xst # st + nice-to-have extensions
(makeDesktopItem {
name = "xst";
desktopName = "Suckless Terminal";
genericName = "Default terminal";
icon = "utilities-terminal";
exec = "${xst}/bin/xst";
categories = "Development;System;Utility";
})
];
};
}

View file

@ -4,10 +4,17 @@
# Liking C/C++ seems to be an unpopular opinion. It's my guilty secret, so don't # Liking C/C++ seems to be an unpopular opinion. It's my guilty secret, so don't
# tell anyone pls. # tell anyone pls.
{ pkgs, ... }: { config, options, lib, pkgs, ... }:
with lib;
{ {
imports = [ ./. ]; options.modules.dev.cc = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.dev.cc.enable {
my.packages = with pkgs; [ my.packages = with pkgs; [
clang clang
gcc gcc
@ -16,4 +23,5 @@
cmake cmake
llvmPackages.libcxx llvmPackages.libcxx
]; ];
};
} }

View file

@ -2,11 +2,21 @@
# #
# I don't use clojure. Perhaps one day... # I don't use clojure. Perhaps one day...
{ pkgs, ... }: { config, options, lib, pkgs, ... }:
with lib;
{ {
options.modules.dev.clojure = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.dev.clojure.enable {
my.packages = with pkgs; [ my.packages = with pkgs; [
clojure clojure
joker joker
leiningen leiningen
]; ];
};
} }

View file

@ -2,10 +2,20 @@
# #
# Mostly for my stumpwm config, and the occasional dip into lisp gamedev. # Mostly for my stumpwm config, and the occasional dip into lisp gamedev.
{ config, lib, pkgs, ... }: { config, options, lib, pkgs, ... }:
with lib;
{ {
options.modules.dev.common-lisp = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.dev.common-lisp.enable {
my.packages = with pkgs; [ my.packages = with pkgs; [
sbcl sbcl
lispPackages.quicklisp lispPackages.quicklisp
]; ];
};
} }

View file

@ -2,7 +2,22 @@
{ pkgs, ... }: { pkgs, ... }:
{ {
my.packages = with pkgs; [ imports = [
gnumake ./cc.nix
./clojure.nix
./common-lisp.nix
# ./godot.nix
# ./haskell.nix
# ./latex.nix
# ./love2d.nix
# ./node.nix
# ./python.nix
./rust.nix
./scala.nix
# ./unity3d.nix
# ./zsh.nix
]; ];
options = {};
config = {};
} }

View file

@ -3,9 +3,19 @@
# Gamedev is my hobby. C++ or Rust are my main drivers (and occasionally Lua), # Gamedev is my hobby. C++ or Rust are my main drivers (and occasionally Lua),
# but to prototype (for 3D, mainly) I'll occasionally reach for godot. # but to prototype (for 3D, mainly) I'll occasionally reach for godot.
{ pkgs, ... }: { config, options, lib, pkgs, ... }:
with lib;
{ {
options.modules.dev.godot = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.dev.godot.enable {
my.packages = with pkgs; [ my.packages = with pkgs; [
godot godot
]; ];
};
} }

View file

@ -7,8 +7,17 @@
# is no formal proof of your claims for safety, but who said you have to solve # is no formal proof of your claims for safety, but who said you have to solve
# all the world's problems to be wonderful? # all the world's problems to be wonderful?
{ lib, pkgs, ... }: { config, options, lib, pkgs, ... }:
with lib;
{ {
options.modules.dev.rust = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.dev.rust.enable {
my = { my = {
packages = with pkgs; [ packages = with pkgs; [
rustup rustup
@ -22,4 +31,5 @@
alias.rsp = "rustup"; alias.rsp = "rustup";
alias.ca = "cargo"; alias.ca = "cargo";
}; };
};
} }

19
modules/dev/scala.nix Normal file
View file

@ -0,0 +1,19 @@
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.dev.scala = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.dev.scala.enable {
my.packages = with pkgs; [
scala
jdk
sbt
];
};
}

View file

@ -0,0 +1,19 @@
{ config, options, lib, pkgs, ... }:
with lib;
{
imports = [
./emacs.nix
./vim.nix
];
options.modules.editors = {
default = mkOption {
type = types.str;
default = "vi";
};
};
config = mkIf (config.modules.editors.default != null) {
my.env.EDITOR = config.modules.editors.default;
};
}

View file

@ -2,8 +2,17 @@
# https://github.com/hlissner/doom-emacs. This module sets it up to meet my # https://github.com/hlissner/doom-emacs. This module sets it up to meet my
# particular Doomy needs. # particular Doomy needs.
{ config, lib, pkgs, ... }: { config, options, lib, pkgs, ... }:
with lib;
{ {
options.modules.editors.emacs = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.editors.emacs.enable {
my = { my = {
packages = with pkgs; [ packages = with pkgs; [
## Doom dependencies ## Doom dependencies
@ -48,4 +57,5 @@
fonts.fonts = [ fonts.fonts = [
pkgs.emacs-all-the-icons-fonts pkgs.emacs-all-the-icons-fonts
]; ];
};
} }

View file

@ -1,17 +1,26 @@
# When I'm stuck in the terminal or don't have access to Emacs, (neo)vim is my # When I'm stuck in the terminal or don't have access to Emacs, (neo)vim is my
# go-to. I am a vimmer at heart, after all. # go-to. I am a vimmer at heart, after all.
{ config, lib, pkgs, ... }: { config, options, lib, pkgs, ... }:
with lib;
{ {
options.modules.editors.vim = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.editors.vim.enable {
my = { my = {
packages = with pkgs; [ packages = with pkgs; [
editorconfig-core-c editorconfig-core-c
neovim neovim
]; ];
env.EDITOR = "nvim";
env.VIMINIT = "let \\$MYVIMRC='\\$XDG_CONFIG_HOME/nvim/init.vim' | source \\$MYVIMRC"; env.VIMINIT = "let \\$MYVIMRC='\\$XDG_CONFIG_HOME/nvim/init.vim' | source \\$MYVIMRC";
alias.vim = "nvim";
alias.v = "nvim"; alias.v = "nvim";
}; };
};
} }

View file

@ -1,8 +0,0 @@
{ config, lib, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
epsxe # PSX
desmume # DS
];
}

View file

@ -1,20 +0,0 @@
{ config, lib, pkgs, ... }:
{
my.packages = with pkgs; [
# Get steam to keep its garbage out of $HOME
(writeScriptBin "steam" ''
#!${stdenv.shell}
HOME="$XDG_DATA_HOME/steamlib" exec ${steam}/bin/steam "$@"
'')
# for GOG and humblebundle games
(writeScriptBin "steam-run" ''
#!${stdenv.shell}
HOME="$XDG_DATA_HOME/steamlib" exec ${steam-run-native}/bin/steam-run "$@"
'')
xboxdrv # driver for 360 controller
];
hardware.opengl.driSupport32Bit = true;
hardware.pulseaudio.support32Bit = true;
}

View file

@ -1,26 +0,0 @@
# modules/graphics.nix
#
# The hardest part about switching to linux? Sacrificing Adobe. It really is
# difficult to replace and its open source alternatives don't *quite* cut it,
# but enough that I can do a fraction of it on Linux. For the rest I have a
# second computer dedicated to design work (and gaming).
{ config, lib, pkgs, ... }:
{
my = {
packages = with pkgs; [
font-manager # so many damned fonts...
imagemagick # for image manipulation from the shell
aseprite-unfree # pixel art
inkscape # illustrator & indesign
krita # replaces photoshop
gimp # replaces photoshop
gimpPlugins.resynthesizer2 # content-aware scaling in gimp
];
home.xdg.configFile = {
"GIMP/2.10" = { source = <config/gimp>; recursive = true; };
};
};
}

View file

@ -0,0 +1,9 @@
{ config, lib, pkgs, ... }:
{
imports = [
./mpv.nix
# ./ncmpcpp.nix
./spotify.nix
];
}

19
modules/media/mpv.nix Normal file
View file

@ -0,0 +1,19 @@
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.media.mpv = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.media.mpv.enable {
my.packages = with pkgs; [
mpv-with-scripts
mpvc # CLI controller for mpv
(mkIf config.services.xserver.enable
celluloid) # nice GTK GUI for mpv
];
};
}

View file

67
modules/media/spotify.nix Normal file
View file

@ -0,0 +1,67 @@
# I use spotify for my music needs. Gone are the days where I'd manage 200gb+ of
# local music; most of which I haven't heard or don't even like.
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.media.spotify = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.media.spotify.enable {
# services.spotifyd doesn't work so we'll have to roll our own spotifyd +
# spotify-tui solution. The dbus interface doesn't work, though, so we have to
# wait for spotify-tui to implement CLI command for controlling spotify
# playback. See https://github.com/Rigellute/spotify-tui/issues/147 or for
# spotifyd to get fixed.
my.packages = with pkgs; [
# unstable.spotifyd
# (writeScriptBin "spt" ''
# #!${stdenv.shell}
# if ! systemctl --user is-active spotifyd >/dev/null; then
# systemctl --user start spotifyd
# fi
# echo $TMUX >$XDG_DATA_HOME/spt.tmux
# exec ${unstable.spotify-tui}/bin/spt
# '')
# spotify-tui is fine for selecting and playing music, but incomplete. We
# occasionally still need the official client for more sophisticated search
# and the "made for you" playlists.
spotify
# Since dbus doesn't work with spotifyd/spotify-tui, and I always use tmux
# for my terminal, may as well exploit tmux to control spotify.
# (writeScriptBin "spt-send" ''
# #!${stdenv.shell}
# dbus_cmd='dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player'
# tmux_cmd="tmux send-keys -t $(cat $XDG_DATA_HOME/spt.tmux | cut -d, -f3)"
# case "$1" in
# toggle) $dbus_cmd.PlayPause 2>/dev/null || $tmux_cmd " " ;;
# next) $dbus_cmd.Next 2>/dev/null || $tmux_cmd n ;;
# prev) $dbus_cmd.Previous 2>/dev/null || $tmux_cmd p ;;
# esac
# '')
];
# systemd.user.services.spotifyd.serviceConfig =
# let spotifydConf = pkgs.writeText "spotifyd.conf" ''
# [global]
# username = g2qwjcs6334oacg1zg9wrihnn
# password_cmd = ${pkgs.pass}/bin/pass www/spotify.com | head -n1
# backend = pulseaudio
# '';
# in {
# ExecStart = ''
# ${pkgs.unstable.spotifyd}/bin/spotifyd --no-daemon \
# --cache-path /tmp/spotifyd \
# --config-path ${spotifydConf}
# '';
# Restart = "always";
# RestartSec = 6;
# };
};
}

View file

@ -1,39 +0,0 @@
# I use spotify for my music needs. Gone are the days where I'd manage 200gb+ of
# local music; most of which I haven't heard or don't even like.
{ config, lib, pkgs, ... }:
{
# services.spotifyd doesn't work so we'll have to roll our own spotifyd +
# spotify-tui solution. The dbus interface doesn't work, though, so we have to
# wait for spotify-tui to implement CLI command for controlling spotify
# playback. See https://github.com/Rigellute/spotify-tui/issues/147 or for
# spotifyd to get fixed.
my.packages = with pkgs; [
unstable.spotifyd
(writeScriptBin "spt" ''
#!${stdenv.shell}
if ! systemctl --user is-active spotifyd >/dev/null; then
systemctl --user start spotifyd
fi
${unstable.spotify-tui}/bin/spt
'')
# spotify-tui is fine for selecting and playing music, but incomplete. We
# occasionally still need the official client for more sophisticated search
# and the "made for you" playlists.
spotify
];
systemd.user.services.spotifyd.serviceConfig =
let spotifydConf = pkgs.writeText "spotifyd.conf" ''
[global]
username = g2qwjcs6334oacg1zg9wrihnn
password_cmd = ${pkgs.pass}/bin/pass www/spotify.com | head -n1
backend = pulseaudio
'';
in {
ExecStart = "${pkgs.unstable.spotifyd}/bin/spotifyd --no-daemon --cache-path /tmp/spotifyd --config-path ${spotifydConf}";
Restart = "always";
RestartSec = 6;
};
}

View file

@ -1,14 +0,0 @@
# modules/recording.nix
#
# OBS to capture footage/stream, DaVinci Resolve for editing (on my Windows
# system -- it will run on linux, but it can't be automated on nix, what with
# their devs registration-gating their free download).
{ config, lib, pkgs, ... }:
{
my.packages = with pkgs; [
audacity # for recording and remastering audio
obs-studio # for streaming to twitch/recording for youtube
handbrake # for encoding footage
];
}

View file

@ -1,6 +0,0 @@
{ config, lib, pkgs, ... }:
{
services.calibre-server.enable = true;
networking.firewall.allowedTCPPorts = [ 8080 ];
}

View file

@ -0,0 +1,15 @@
{ config, options, pkgs, lib, ... }:
with lib;
{
options.modules.services.calibre = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.services.calibre.enable {
services.calibre-server.enable = true;
networking.firewall.allowedTCPPorts = [ 8080 ];
};
}

View file

@ -0,0 +1,16 @@
{ config, lib, pkgs, ... }:
{
imports = [
# ./calibre-server.nix
# ./gitea.nix
# ./jellyfin.nix
# ./keybase.nix
# ./mpd.nix
# ./nginx.nix
# ./plex.nix
# ./ssh.nix
./syncthing.nix
# ./transmission.nix
];
}

View file

@ -1,6 +1,14 @@
{ config, lib, pkgs, ... }: { config, options, pkgs, lib, ... }:
with lib;
{ {
options.modules.services.gitea = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.services.gitea.enable {
# I prefer git@... ssh addresses over gitea@... # I prefer git@... ssh addresses over gitea@...
users.users.git = { users.users.git = {
useDefaultShell = true; useDefaultShell = true;
@ -23,4 +31,5 @@
# We're assuming SSL-only connectivity # We're assuming SSL-only connectivity
cookieSecure = true; cookieSecure = true;
}; };
};
} }

View file

@ -1,8 +1,16 @@
# Finally, a decent open alternative to Plex! # Finally, a decent open alternative to Plex!
{ config, lib, pkgs, ... }: { config, options, pkgs, lib, ... }:
with lib;
{ {
options.modules.services.jellyfin = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.services.jellyfin.enable {
services.jellyfin.enable = true; services.jellyfin.enable = true;
networking.firewall = { networking.firewall = {
@ -11,4 +19,5 @@
}; };
my.user.extraGroups = [ "jellyfin" ]; my.user.extraGroups = [ "jellyfin" ];
};
} }

View file

@ -0,0 +1,14 @@
{ config, lib, pkgs, ... }:
{
services.kbfs = {
enable = true;
mountPoint = "%t/kbfs";
extraFlags = [ "-label %u" ];
};
systemd.user.services.kbfs = {
environment = { KEYBASE_RUN_MODE = "prod"; };
serviceConfig.Slice = "keybase.slice";
};
}

View file

@ -5,6 +5,8 @@
mpc_cli mpc_cli
]; ];
my.env.MPD_HOME = "$XDG_CONFIG_HOME/mpd";
services.mpd = { services.mpd = {
enable = true; enable = true;
musicDirectory = "/home/hlissner/music"; musicDirectory = "/home/hlissner/music";

View file

@ -1,6 +1,14 @@
{ config, lib, pkgs, ... }: { config, options, pkgs, lib, ... }:
with lib;
{ {
options.modules.services.nginx = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.services.nginx.enable {
networking.firewall.allowedTCPPorts = [ 80 443 ]; networking.firewall.allowedTCPPorts = [ 80 443 ];
services.nginx = { services.nginx = {
@ -12,4 +20,5 @@
recommendedProxySettings = true; recommendedProxySettings = true;
recommendedTlsSettings = true; recommendedTlsSettings = true;
}; };
};
} }

View file

@ -1,6 +1,16 @@
{ config, pkgs, ... }: { config, pkgs, ... }:
{ config, options, pkgs, lib, ... }:
with lib;
{ {
options.modules.services.ssh = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.services.ssh.enable {
services.openssh = { services.openssh = {
enable = true; enable = true;
forwardX11 = true; forwardX11 = true;
@ -17,4 +27,5 @@
users.users.hlissner.openssh.authorizedKeys.keys = [ users.users.hlissner.openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8Tl2pj6CPBV3V72cohPhn+k0a/Na3cOrbmUtFC7rR7icWocSs1S1cSrP3sPLwUqRh3+zfIuLXTrTv3gj8Xvg8WELOspzsiYeAtbcHrnWnx/a7xzYvFyT9/8hkiGM/F6w7IuKEk+AZW34vARSgRPJ1FdH8NbPKJ8ay9zW9XB9YJGnbzIRmsVVpQ8l6Fh8ZqRjZfC1ea7hns8+HgjPrIHFb+S3qZZiwU4Gc8aWJy9ziwwkllEsSchv3aigYA3eOeW0FUQFiKsLGxbX2b2b3d6jFO4Pu+dMSen0h5IzBo0nh7UADSfJPdwbZaMuJzviKe2y6zg6jaM9XRIhLBT6bftDr henrik@lissner.net" "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8Tl2pj6CPBV3V72cohPhn+k0a/Na3cOrbmUtFC7rR7icWocSs1S1cSrP3sPLwUqRh3+zfIuLXTrTv3gj8Xvg8WELOspzsiYeAtbcHrnWnx/a7xzYvFyT9/8hkiGM/F6w7IuKEk+AZW34vARSgRPJ1FdH8NbPKJ8ay9zW9XB9YJGnbzIRmsVVpQ8l6Fh8ZqRjZfC1ea7hns8+HgjPrIHFb+S3qZZiwU4Gc8aWJy9ziwwkllEsSchv3aigYA3eOeW0FUQFiKsLGxbX2b2b3d6jFO4Pu+dMSen0h5IzBo0nh7UADSfJPdwbZaMuJzviKe2y6zg6jaM9XRIhLBT6bftDr henrik@lissner.net"
]; ];
};
} }

View file

@ -1,6 +1,14 @@
{ config, lib, pkgs, ... }: { config, options, pkgs, lib, ... }:
with lib;
{ {
options.modules.services.syncthing = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.services.syncthing.enable {
services.syncthing = { services.syncthing = {
enable = true; enable = true;
openDefaultPorts = true; openDefaultPorts = true;
@ -57,4 +65,5 @@
}; };
}; };
}; };
};
} }

15
modules/shell/default.nix Normal file
View file

@ -0,0 +1,15 @@
{ config, lib, pkgs, ... }:
{
imports = [
./direnv.nix
./git.nix
./gnupg.nix
./ncmpcpp.nix
./pass.nix
./ranger.nix
./tmux.nix
./weechat.nix
./zsh.nix
];
}

View file

@ -1,10 +1,17 @@
{ config, lib, pkgs, ... }: { config, options, lib, pkgs, ... }:
with lib;
{ {
services.lorri.enable = true; options.modules.shell.direnv = {
enable = mkOption { type = types.bool; default = false; };
};
config = mkIf config.modules.shell.direnv.enable {
my = { my = {
packages = [ pkgs.direnv ]; packages = [ pkgs.direnv ];
zsh.rc = "_cache direnv hook zsh"; zsh.rc = "_cache direnv hook zsh";
}; };
services.lorri.enable = true;
};
} }

View file

@ -1,6 +1,15 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
with lib;
{ {
options.modules.shell.git = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.shell.git.enable {
my = { my = {
packages = with pkgs; [ packages = with pkgs; [
gitAndTools.hub gitAndTools.hub
@ -13,4 +22,5 @@
"git/ignore".source = <config/git/ignore>; "git/ignore".source = <config/git/ignore>;
}; };
}; };
};
} }

View file

@ -1,6 +1,15 @@
{ config, lib, pkgs, ... }: { config, options, lib, pkgs, ... }:
{ with lib;
let cfg = config.modules;
gnupgCfg = cfg.shell.gnupg;
in {
options.modules.shell.gnupg = {
enable = mkOption { type = types.bool; default = false; };
cacheTTL = mkOption { type = types.int; default = 1800; };
};
config = mkIf gnupgCfg.enable {
my = { my = {
packages = with pkgs; [ packages = with pkgs; [
gnupg gnupg
@ -20,8 +29,9 @@
${pkgs.gnupg}/bin/gpg-agent \ ${pkgs.gnupg}/bin/gpg-agent \
--supervised \ --supervised \
--allow-emacs-pinentry \ --allow-emacs-pinentry \
--default-cache-ttl 1800 \ --default-cache-ttl ${toString gnupgCfg.cacheTTL} \
--pinentry-program ${pkgs.pinentry}/bin/pinentry-gtk-2 --pinentry-program ${pkgs.pinentry}/bin/pinentry-gtk-2
'' ''
]; ];
};
} }

View file

@ -1,21 +1,29 @@
{ config, lib, pkgs, ... }: { config, options, lib, pkgs, ... }:
with lib;
{ {
options.modules.shell.ncmpcpp = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.shell.ncmpcpp.enable {
my.packages = with pkgs; [ my.packages = with pkgs; [
(ncmpcpp.override { visualizerSupport = true; }) (ncmpcpp.override { visualizerSupport = true; })
]; ];
my.env.MPD_HOME = "$XDG_CONFIG_HOME/mpd";
my.env.NCMPCPP_HOME = "$XDG_CONFIG_HOME/ncmpcpp";
my.alias.rate = "mpd-rate"; my.alias.rate = "mpd-rate";
my.alias.mpcs = "mpc search any"; my.alias.mpcs = "mpc search any";
my.alias.mpcsp = "mpc searchplay any"; my.alias.mpcsp = "mpc searchplay any";
my.env.NCMPCPP_HOME = "$XDG_CONFIG_HOME/ncmpcpp";
# Symlink these one at a time because ncmpcpp writes other files to # Symlink these one at a time because ncmpcpp writes other files to
# ~/.config/ncmpcpp, so it needs to be writeable. # ~/.config/ncmpcpp, so it needs to be writeable.
my.home.xdg.configFile = { my.home.xdg.configFile = {
"ncmpcpp/config".source = <config/ncmpcpp/config>; "ncmpcpp/config".source = <config/ncmpcpp/config>;
"ncmpcpp/bindings".source = <config/ncmpcpp/bindings>; "ncmpcpp/bindings".source = <config/ncmpcpp/bindings>;
}; };
};
} }

View file

@ -1,6 +1,14 @@
{ config, pkgs, lib, ... }: { config, options, pkgs, lib, ... }:
with lib;
{ {
options.modules.shell.pass = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.shell.pass.enable {
my = { my = {
packages = with pkgs; [ packages = with pkgs; [
(pass.withExtensions (exts: [ (pass.withExtensions (exts: [
@ -10,4 +18,5 @@
]; ];
env.PASSWORD_STORE_DIR = "$HOME/.secrets/password-store"; env.PASSWORD_STORE_DIR = "$HOME/.secrets/password-store";
}; };
};
} }

View file

@ -1,9 +1,18 @@
{ config, lib, pkgs, ... }: { config, options, pkgs, lib, ... }:
with lib;
{ {
options.modules.shell.ranger = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.shell.ranger.enable {
my.packages = with pkgs; [ my.packages = with pkgs; [
ranger ranger
(lib.mkIf config.services.xserver.enable # For image previews
w3m) (lib.mkIf config.services.xserver.enable w3m)
]; ];
};
} }

View file

@ -1,6 +1,14 @@
{ config, lib, pkgs, ... }: { config, options, pkgs, lib, ... }:
with lib;
{ {
options.modules.shell.tmux = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.shell.tmux.enable {
my = { my = {
packages = with pkgs; [ packages = with pkgs; [
# The developer of tmux chooses not to add XDG support for religious # The developer of tmux chooses not to add XDG support for religious
@ -29,4 +37,5 @@
''; '';
}; };
}; };
};
} }

17
modules/shell/weechat.nix Normal file
View file

@ -0,0 +1,17 @@
{ config, options, lib, pkgs, ... }:
with lib;
{
options.modules.shell.weechat = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.shell.weechat.enable {
my.packages = with pkgs; [
weechat
];
};
}

View file

@ -1,7 +1,16 @@
# modules/shell/zsh.nix --- ... # modules/shell/zsh.nix --- ...
{ pkgs, libs, ... }: { config, options, pkgs, lib, ... }:
with lib;
{ {
options.modules.shell.zsh = {
enable = mkOption {
type = types.bool;
default = false;
};
};
config = mkIf config.modules.shell.zsh.enable {
my = { my = {
packages = with pkgs; [ packages = with pkgs; [
zsh zsh
@ -45,4 +54,5 @@
system.userActivationScripts.cleanupZgen = '' system.userActivationScripts.cleanupZgen = ''
rm -fv $XDG_CACHE_HOME/zsh/* rm -fv $XDG_CACHE_HOME/zsh/*
''; '';
};
} }

View file

@ -1,10 +1,21 @@
# modules/themes/aquanaut/default.nix --- a sea-blue linux theme # themes/aquanaut/default.nix --- a sea-blue linux theme
{ config, lib, pkgs, ... }: { config, options, lib, pkgs, ... }:
with lib;
{ {
imports = [ ../. ]; # Load framework for themes options.modules.themes.aquanaut = {
enable = mkOption {
type = types.bool;
default = false;
};
};
theme.wallpaper = ./wallpaper.jpg; config = mkIf config.modules.themes.aquanaut.enable {
modules.theme = {
name = "Aquanaut";
version = "0.1";
path = ./.;
};
services.compton = { services.compton = {
activeOpacity = "0.96"; activeOpacity = "0.96";
@ -65,4 +76,5 @@
style=Nordic-blue style=Nordic-blue
''; '';
}; };
};
} }

View file

@ -1,16 +1,56 @@
# modules/themes/default.nix { config, options, lib, pkgs, ... }:
{ config, ... }: with lib;
{ {
imports = [ ./options.nix ]; imports = [
# aquanaut = callPackage (import ./aquanaut {});
./fluorescence
];
# Try really hard to get QT to respect my GTK theme. options.modules.theme = {
my.env.GTK_DATA_PREFIX = [ "${config.system.path}" ]; name = mkOption { type = with types; nullOr str; default = null; };
my.env.QT_QPA_PLATFORMTHEME = "gtk2"; version = mkOption { type = with types; nullOr str; default = null; };
qt5 = { style = "gtk2"; platformTheme = "gtk2"; }; path = mkOption {
services.xserver.displayManager.sessionCommands = '' type = with types; nullOr path;
export GTK2_RC_FILES="$XDG_CONFIG_HOME/gtk-2.0/gtkrc" default = null;
source "$XDG_CONFIG_HOME"/xsession/*.sh };
xrdb -merge "$XDG_CONFIG_HOME"/xtheme/*
wallpaper = {
path = mkOption {
type = with types; nullOr str;
default = if config.modules.theme.path != null
then "${config.modules.theme.path}/wallpaper.png"
else null;
};
filter = {
enable = mkOption {
type = types.bool;
default = true;
};
options = mkOption {
type = types.str;
default = "-gaussian-blur 0x2 -modulate 70 -level 5%";
};
};
};
};
config = mkIf (config.modules.theme.wallpaper.path != null &&
builtins.pathExists config.modules.theme.wallpaper.path) {
my.home.home.file.".background-image".source =
config.modules.theme.wallpaper.path;
services.xserver.displayManager.lightdm.background =
mkIf config.modules.theme.wallpaper.filter.enable
(let filteredPath = "wallpaper.filtered.png";
filteredWallpaper =
with pkgs; runCommand "filterWallpaper"
{ buildInputs = [ imagemagick ]; } ''
mkdir "$out"
convert ${config.modules.theme.wallpaper.filter.options} \
${config.modules.theme.wallpaper.path} $out/${filteredPath}
''; '';
in "${filteredWallpaper}/${filteredPath}");
};
} }

View file

@ -1,10 +1,25 @@
# modules/themes/aquanaut/default.nix --- a sea-blue linux theme # themes/fluorescence/default.nix --- a regal dracula-inspired theme
{ config, lib, pkgs, ... }: { config, options, lib, pkgs, ... }:
with lib;
{ {
imports = [ ../. ]; # Load framework for themes options.modules.themes.fluorescence = {
enable = mkOption {
type = types.bool;
default = false;
};
};
theme.wallpaper = ./wallpaper.png; config = mkIf config.modules.themes.fluorescence.enable {
modules.theme = {
name = "fluorescence";
version = "0.0.1";
path = ./.;
wallpaper = {
filter.options = "-gaussian-blur 0x2 -modulate 70 -level 5%";
};
};
services.compton = { services.compton = {
fade = true; fade = true;
@ -40,7 +55,8 @@
paper-icon-theme # for rofi paper-icon-theme # for rofi
]; ];
my.zsh.rc = lib.readFile ./zsh/prompt.zsh; my.zsh.rc = lib.readFile ./zsh/prompt.zsh;
my.home.xdg.configFile = { my.home.xdg = {
configFile = {
"bspwm/rc.d/polybar".source = ./polybar/run.sh; "bspwm/rc.d/polybar".source = ./polybar/run.sh;
"bspwm/rc.d/theme".source = ./bspwmrc; "bspwm/rc.d/theme".source = ./bspwmrc;
"dunst/dunstrc".source = ./dunstrc; "dunst/dunstrc".source = ./dunstrc;
@ -72,4 +88,24 @@
style=Ant-Dracula style=Ant-Dracula
''; '';
}; };
dataFile = mkIf config.modules.desktop.browsers.qutebrowser.enable {
"qutebrowser/userstyles.css".source =
let compiledStyles =
with pkgs; runCommand "compileUserStyles"
{ buildInputs = [ sass ]; } ''
mkdir "$out"
for file in ${./userstyles/qutebrowser}/*.scss; do
scss --sourcemap=none \
--no-cache \
--style compressed \
--default-encoding utf-8 \
"$file" \
>>"$out/userstyles.css"
done
'';
in "${compiledStyles}/userstyles.css";
};
};
};
} }

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,3 @@
textarea {
font-family: monospace;
}

View file

@ -1,27 +0,0 @@
# modules/themes/options.nix
{ options, config, lib, pkgs, ... }:
with lib;
{
options.theme = {
wallpaper = mkOption {
type = with types; nullOr (either str path);
};
# TODO Colors?
};
config = {
my.home.home.file.".background-image".source = config.theme.wallpaper;
services.xserver.displayManager.lightdm.background =
let blurredWallpaper =
with pkgs; runCommand "blurWallpaper"
{ buildInputs = [ imagemagick ]; } ''
mkdir "$out"
convert -gaussian-blur 0x2 -modulate 70 -level 5% \
${config.theme.wallpaper} $out/wallpaper.blurred.png
'';
in mkIf (config.theme.wallpaper != null)
"${blurredWallpaper}/wallpaper.blurred.png";
};
}

View file

@ -1,14 +0,0 @@
# modules/vm.nix
#
# For testing software or building it on other OSes. If I find out how to get
# macOS on qemu/libvirt I'd be happy to leave virtualbox behind.
{ config, lib, pkgs, ... }:
{
virtualisation.virtualbox.host = {
enable = true;
enableExtensionPack = true; # urg, takes so long to build
};
my.user.extraGroups = [ "vboxusers" ];
}

View file

@ -1,89 +0,0 @@
{ config, options, lib, ... }:
with lib;
let mkOptionStr = value: mkOption
{ type = types.str;
default = value; };
in
{
imports = [ <home-manager/nixos> ];
## Personal settings
options.my.username = mkOptionStr "hlissner";
options.my.email = mkOptionStr "henrik@lissner.net";
## Convenience aliases
options.my.home = mkOption
{ type = options.home-manager.users.type.functor.wrapped; };
config.home-manager.users.${config.my.username} = mkAliasDefinitions options.my.home;
options.my.user = mkOption { type = types.submodule; };
config.users.users.${config.my.username} = mkAliasDefinitions options.my.user;
options.my.packages = mkOption
{ type = types.listOf types.package;
description = "The set of packages to appear in the user environment."; };
config.my.user.packages = config.my.packages;
## Shell/Environment
options.my.env = mkOption {
type = with types; attrsOf (either (either str path) (listOf (either str path)));
apply = mapAttrs
(n: v: if isList v
then concatMapStringsSep ":" (x: toString x) v
else (toString v));
};
options.my.init = mkOption {
type = types.lines;
description = ''
An init script that runs after the environment has been rebuilt or
booted. Anything done here should be idempotent and inexpensive.
'';
};
## PATH should always start with its old value
config.my.env.PATH = [ ./bin "$PATH" ];
config.environment.extraInit =
let exportLines = mapAttrsToList (n: v: "export ${n}=\"${v}\"") config.my.env;
in ''
${concatStringsSep "\n" exportLines}
${config.my.init}
'';
options.my.alias = mkOption
{ type = with types; nullOr (attrsOf (nullOr (either str path))); };
options.my.zsh = {
rc = mkOption {
type = types.lines;
default = "";
description = ''
Zsh lines to be written to $XDG_CONFIG_HOME/zsh/extra.zshrc and
sourced by $XDG_CONFIG_HOME/zsh/.zshrc
'';
};
env = mkOption {
type = types.lines;
default = "";
description = ''
Zsh lines to be written to $XDG_CONFIG_HOME/zsh/extra.zshenv and
sourced by $XDG_CONFIG_HOME/zsh/.zshenv
'';
};
};
# I avoid programs.zsh.*Init variables because they initialize too soon. My
# zsh config is particular about load order.
config.my.home.xdg.configFile."zsh/extra.zshrc".text =
let aliasLines = mapAttrsToList (n: v: "alias ${n}=\"${v}\"") config.my.alias;
in ''
# This file is autogenerated, do not edit it!
${concatStringsSep "\n" aliasLines}
${config.my.zsh.rc}
'';
config.my.home.xdg.configFile."zsh/extra.zshenv".text = ''
# This file is autogenerated, do not edit it!
${config.my.zsh.env};
'';
}