aboutsummaryrefslogtreecommitdiff
path: root/home/profiles
diff options
context:
space:
mode:
authorFranck Cuny <franck@fcuny.net>2023-05-05 19:41:58 -0700
committerFranck Cuny <franck@fcuny.net>2023-05-05 19:41:58 -0700
commit43da9edb4598eef509c481ae0b305384418c45de (patch)
treea0ad614c90102757143e026e4fe1806431a3dbf4 /home/profiles
parentprofiles/default: users are immutable (diff)
downloadinfra-43da9edb4598eef509c481ae0b305384418c45de.tar.gz
home/profiles: move (almost) all modules to profiles
This is a major refactor, similar to what was done for the hosts, but in a single commit.
Diffstat (limited to 'home/profiles')
-rw-r--r--home/profiles/alacritty.nix51
-rw-r--r--home/profiles/dev.nix49
-rw-r--r--home/profiles/emacs.nix13
-rw-r--r--home/profiles/firefox.nix59
-rw-r--r--home/profiles/git.nix73
-rw-r--r--home/profiles/gtk.nix35
-rw-r--r--home/profiles/home.nix69
-rw-r--r--home/profiles/mako.nix25
-rw-r--r--home/profiles/nas.nix67
-rw-r--r--home/profiles/ssh.nix18
-rw-r--r--home/profiles/sway.nix172
-rw-r--r--home/profiles/tmux.nix20
-rw-r--r--home/profiles/waybar.nix155
-rw-r--r--home/profiles/wofi.nix13
-rw-r--r--home/profiles/workstation.nix113
-rw-r--r--home/profiles/ytdlp.nix37
-rw-r--r--home/profiles/yubikey.nix28
-rw-r--r--home/profiles/zsh/completion-style.zsh42
-rw-r--r--home/profiles/zsh/default.nix51
-rw-r--r--home/profiles/zsh/new-go-project.zsh19
-rw-r--r--home/profiles/zsh/options.zsh27
-rw-r--r--home/profiles/zsh/prompt.zsh17
-rw-r--r--home/profiles/zsh/tmux.zsh9
23 files changed, 1162 insertions, 0 deletions
diff --git a/home/profiles/alacritty.nix b/home/profiles/alacritty.nix
new file mode 100644
index 0000000..2789f12
--- /dev/null
+++ b/home/profiles/alacritty.nix
@@ -0,0 +1,51 @@
+{
+ programs.alacritty = {
+ enable = true;
+ settings = {
+ env = {
+ TERM = "xterm-256color";
+ };
+
+ live_config_reload = true;
+ draw_bold_text_with_bright_colors = true;
+ selection = { save_to_clipboard = true; };
+
+ colors = {
+ primary = {
+ background = "#000000";
+ foreground = "#D3D7CF";
+ };
+
+ normal = {
+ black = "#2E3436";
+ red = "#CC0000";
+ green = "#4E9A06";
+ yellow = "#C4A000";
+ blue = "#3465A4";
+ magenta = "#EF33C0";
+ cyan = "#04B5B8";
+ white = "#D3D7CF";
+ };
+
+ bright = {
+ black = "#555753";
+ red = "#EF2929";
+ green = "#8AE234";
+ yellow = "#FCE94F";
+ blue = "#729FCF";
+ magenta = "#EE38DA";
+ cyan = "#34E2E2";
+ white = "#EEEEEC";
+ };
+ };
+ font = {
+ size = 13;
+ normal.family = "Source Code Pro";
+ };
+ cursor = {
+ style.blinking = "Never";
+ unfocused_hollow = true;
+ };
+ };
+ };
+}
diff --git a/home/profiles/dev.nix b/home/profiles/dev.nix
new file mode 100644
index 0000000..c1323d6
--- /dev/null
+++ b/home/profiles/dev.nix
@@ -0,0 +1,49 @@
+{ pkgs, config, ... }:
+let
+ ruststable = (pkgs.rust-bin.stable.latest.default.override {
+ extensions = [
+ "rust-src"
+ "rust-analyzer-preview"
+ "rust-analysis"
+ "rustfmt-preview"
+ ];
+ });
+ pythonEnv = pkgs.python3.withPackages (p: with p; [
+ black
+ isort
+ pylsp-mypy
+ requests
+ types-requests
+ pip
+ ipython
+ ]);
+in
+{
+ programs.go = {
+ enable = true;
+ goPath = ".local/share/pkg.go";
+ goBin = ".local/bin.go";
+ goPrivate = [ "git.fcuny.net" "golang.fcuny.net" ];
+ package = pkgs.go_1_18;
+ };
+
+ home.packages = with pkgs; [
+ go-tools
+ pythonEnv
+ google-cloud-sdk
+ ruststable
+ ];
+
+ home.sessionPath = [
+ config.home.sessionVariables.GOBIN
+ "$CARGO_HOME/bin"
+ ];
+
+ home.sessionVariables = with config.xdg; {
+ IPYTHONDIR = "${cacheHome}/ipython";
+ PIP_LOG = "${cacheHome}/pip/pip.log";
+ PYLINTHOME = "${cacheHome}/pylint";
+ PYTHON_EGG_CACHE = "${cacheHome}/python-eggs";
+ CARGO_HOME = "${dataHome}/cargo";
+ };
+}
diff --git a/home/profiles/emacs.nix b/home/profiles/emacs.nix
new file mode 100644
index 0000000..17c751d
--- /dev/null
+++ b/home/profiles/emacs.nix
@@ -0,0 +1,13 @@
+{ lib, config, pkgs, ... }:
+{
+ home.packages = with pkgs; [
+ emacsPgtk
+ # see https://github.com/hlissner/doom-emacs/issues/4138
+ (aspellWithDicts (dicts: with dicts; [ en en-computers en-science ]))
+ ];
+
+ home.sessionVariables = {
+ EDITOR = "emacsclient -a=";
+ VISUAL = "emacsclient -a=";
+ };
+}
diff --git a/home/profiles/firefox.nix b/home/profiles/firefox.nix
new file mode 100644
index 0000000..e74aaea
--- /dev/null
+++ b/home/profiles/firefox.nix
@@ -0,0 +1,59 @@
+{ pkgs, lib, config, ... }:
+{
+ programs.firefox = {
+ enable = true;
+ profiles = {
+ default = {
+ extensions = with pkgs.nur.repos.rycee.firefox-addons; [
+ pkgs.nur.repos.rycee.firefox-addons."1password-x-password-manager"
+ consent-o-matic
+ refined-github
+ sponsorblock
+ ublock-origin
+ ];
+ settings = {
+ ## nix handle updates
+ "app.update.auto" = false;
+ "browser.bookmarks.showMobileBookmarks" = false;
+ "browser.compactmode.show" = true;
+ "browser.contentblocking.category" = "strict";
+ "browser.search.countryCode" = "US";
+ "browser.search.defaultenginename" = "DuckDuckGo";
+ "browser.search.isUS" = true;
+ "browser.search.region" = "US";
+ "browser.search.selectedEngine" = "DuckDuckGo";
+ ## don't check if it's the default browser
+ "browser.shell.checkDefaultBrowser" = false;
+ "browser.startup.homepage" = "https://duckduckgo.com";
+ "browser.urlbar.placeholderName" = "DuckDuckGo";
+ ## keep this with ff 96
+ "media.ffmpeg.vaapi.enabled" = true;
+ ## remove on ff 96
+ "media.ffvpx.enabled" = false;
+ ## remove on ff 96
+ "media.navigator.mediadatadecoder_vpx_enabled" = true;
+ "media.peerconnection.enabled" = true;
+ ## keep this with ff 96
+ "media.rdd-ffmpeg.enabled" = true;
+ ## remove on ff 96
+ "media.rdd-vpx.enabled" = false;
+ ## Block third-party cookies
+ "network.cookie.cookieBehavior" = 1;
+ "privacy.donottrackheader.enabled" = true;
+ "privacy.trackingprotection.enabled" = true;
+ "privacy.trackingprotection.socialtracking.enabled" = true;
+
+ "font.name.monospace.x-western" = "Source Code Pro";
+ "font.name.sans-serif.x-western" = "DejaVu Sans";
+ "font.name.serif.x-western" = "DejaVu Serif";
+ };
+
+ userChrome = ''
+ #TabsToolbar {
+ visibility: collapse;
+ }
+ '';
+ };
+ };
+ };
+}
diff --git a/home/profiles/git.nix b/home/profiles/git.nix
new file mode 100644
index 0000000..de2cbf6
--- /dev/null
+++ b/home/profiles/git.nix
@@ -0,0 +1,73 @@
+{ self, lib, pkgs, config, ... }:
+let
+ sshPub = builtins.fromTOML (
+ builtins.readFile "${self}/configs/ssh-pubkeys.toml"
+ );
+in
+{
+ home.file.".ssh/allowed_signers".text = lib.concatMapStrings (x: "franck@fcuny.net ${x}\n") (with sshPub; [ aptos work git ykey-laptop ]);
+
+ programs.git = {
+ enable = true;
+ userName = "Franck Cuny";
+ userEmail = "franck@fcuny.net";
+
+ signing = {
+ key = "key::${sshPub.ykey-laptop}";
+ signByDefault = true;
+ };
+
+ extraConfig = {
+ core.whitespace = "trailing-space,space-before-tab";
+ color.ui = "true";
+
+ diff.age.textconv = "${pkgs.age}/bin/age --identity ${config.home.homeDirectory}/.age/key.txt --decrypt";
+
+ gpg.format = "ssh";
+ gpg.ssh.allowedSignersFile = "~/.ssh/allowed_signers";
+
+ # abort if the remote branch does not match the local one
+ push.default = "simple";
+
+ init.defaultBranch = "main";
+
+ pull.rebase = true;
+ rebase = {
+ # Automatically create a temporary stash entry before the
+ # operation begins, and apply it after the operation ends.
+ autoStash = true;
+ # Print a warning if some commits are removed
+ missingCommitsCheck = "warn";
+ };
+
+ branch.autosetuprebase = "remote";
+ branch.sort = "authordate";
+
+ commit.template = "${config.xdg.dataHome}/git/commit.template";
+ };
+
+ ignores = [
+ "*~"
+ ".direnv"
+ ];
+ };
+
+ xdg.dataFile."git/commit.template".source = pkgs.writeText "commit.template" ''
+
+ # (If applied, this commit will...) <subject>
+
+ # Explain why this change is being made
+
+ # --- COMMIT END ---
+ # Remember to
+ # Use the imperative mood, present tense: `change' not `changed' nor `changes'
+ # Do not end the subject line with a period
+ # Use the body to explain what and why vs. how
+ # Can use multiple lines with "-" for bullet points in body
+'';
+
+ home.packages = with pkgs; [
+ tools.git-blame-stats
+ gitAndTools.pre-commit
+ ];
+}
diff --git a/home/profiles/gtk.nix b/home/profiles/gtk.nix
new file mode 100644
index 0000000..a3fff9d
--- /dev/null
+++ b/home/profiles/gtk.nix
@@ -0,0 +1,35 @@
+{ config, lib, pkgs, ... }:
+{
+ gtk = {
+ enable = true;
+
+ iconTheme = {
+ name = "Papirus-Dark";
+ package = pkgs.papirus-icon-theme;
+ };
+
+ theme = {
+ name = "palenight";
+ package = pkgs.palenight-theme;
+ };
+
+ cursorTheme = {
+ name = "Numix-Cursor";
+ package = pkgs.numix-cursor-theme;
+ };
+
+ gtk3.extraConfig = {
+ Settings = ''
+ gtk-application-prefer-dark-theme=1
+ '';
+ };
+
+ gtk4.extraConfig = {
+ Settings = ''
+ gtk-application-prefer-dark-theme=1
+ '';
+ };
+ };
+
+ home.sessionVariables.GTK_THEME = "palenight";
+}
diff --git a/home/profiles/home.nix b/home/profiles/home.nix
new file mode 100644
index 0000000..1aa90cf
--- /dev/null
+++ b/home/profiles/home.nix
@@ -0,0 +1,69 @@
+{ config, lib, pkgs, ... }:
+{
+ imports = [
+ ./git.nix
+ ./ssh.nix
+ ./zsh
+ ];
+
+ home.packages = with pkgs; [
+ dive # explore layers in docker images
+ jq
+ ripgrep
+ util-linux
+ xdg-utils
+
+ age
+ rage
+ age-plugin-yubikey
+
+ # tools inside the tools directory
+ tools.git-blame-stats
+ tools.git-broom
+ tools.ipconverter
+ tools.seqstat
+
+ # tools from external repositories
+ # x509-info
+ # gh-ssh-keys
+ # masked-emails
+ ];
+
+ programs.direnv = {
+ enable = true;
+ nix-direnv.enable = true;
+ config = {
+ global.disable_stdin = true;
+ global.strict_env = true;
+ };
+ };
+
+ xdg = {
+ enable = true;
+ # File types
+ mime.enable = true;
+ # File associatons
+ mimeApps = { enable = true; };
+ # User directories
+ userDirs = {
+ enable = true;
+ createDirectories = true;
+ desktop = "${config.home.homeDirectory}/documents";
+ documents = "${config.home.homeDirectory}/documents";
+ download = "${config.home.homeDirectory}/downloads";
+ music = "${config.home.homeDirectory}/media/music";
+ pictures = "${config.home.homeDirectory}/media/pictures";
+ publicShare = "${config.home.homeDirectory}/documents/public";
+ templates = "${config.home.homeDirectory}/documents/templates";
+ videos = "${config.home.homeDirectory}/media/videos";
+ };
+ };
+
+ home.sessionVariables = with config.xdg; {
+ LESS = "-FRSXM";
+ LESSCHARSET = "utf-8";
+ LESSHISTFILE = "${dataHome}/less/history";
+ LESSKEY = "${configHome}/less/lesskey";
+ PAGER = "less";
+ };
+}
diff --git a/home/profiles/mako.nix b/home/profiles/mako.nix
new file mode 100644
index 0000000..d4e54fe
--- /dev/null
+++ b/home/profiles/mako.nix
@@ -0,0 +1,25 @@
+{ config, lib, pkgs, ... }:
+{
+ home.packages = [
+ pkgs.libnotify
+ ];
+
+ # All the options are documented via `man 5 mako`
+ services.mako = {
+ enable = true;
+ font = "Source Code Pro";
+ backgroundColor = "#000021DD";
+ textColor = "#FFFFFFFF";
+ borderSize = 0;
+ borderRadius = 15;
+ icons = true;
+ iconPath = "${pkgs.moka-icon-theme}/share/icons/Moka";
+ markup = true;
+ actions = true;
+ defaultTimeout = 3000;
+ padding = "20";
+ height = 200;
+ width = 500;
+ layer = "overlay";
+ };
+}
diff --git a/home/profiles/nas.nix b/home/profiles/nas.nix
new file mode 100644
index 0000000..c1e5ca9
--- /dev/null
+++ b/home/profiles/nas.nix
@@ -0,0 +1,67 @@
+{ config, lib, pkgs, ... }:
+let
+ bc-to-beet = pkgs.writeShellApplication {
+ name = "bc-to-beet";
+ runtimeInputs = [ pkgs.beets ];
+ text = ''
+ ALBUM_PATH="$1"
+ ALBUM_NAME=$(basename "$ALBUM_PATH")
+
+ mkdir -p ~/import
+ rm -rf ~/import/tmp-bc
+ unzip -d ~/import/tmp-bc ~/import/album.zip
+ beet import ~/import/tmp-bc
+ rm -rf ~/import/tmp-bc
+ rm -rf ~/import/album.zip
+ '';
+ };
+in
+{
+ imports = [
+ ./ytdlp.nix
+ ];
+
+ home.packages = with pkgs; [
+ bc-to-beet
+ flac
+ abcde
+ (pkgs.writers.writeDashBin "rip-flac" ''
+ cd ~/import
+ ${pkgs.abcde}/bin/abcde -Vx -G -a "cddb,read,encode,tag,move,clean" -o flac
+ '')
+ ];
+
+ programs.beets = {
+ enable = true;
+ settings = {
+ directory = cfg.musicDirectory;
+ plugins =
+ "fromfilename discogs duplicates fetchart embedart badfiles lastgenre scrub";
+ paths = {
+ default = "$albumartist/$album%aunique{}/$track $title";
+ singleton = "Singles/$artist/$title";
+ comp = "Compilations/$album%aunique{}/$track - $title";
+ "albumtype:soundtrack" = "Soundtracks/$album ($year)/$track $title";
+ };
+ import = {
+ copy = true;
+ move = true;
+ };
+ va_name = "Various Artists";
+ embedart = { ifempty = true; };
+
+ lastgenre = {
+ auto = false;
+ canonical = true;
+ fallback = "unknown";
+ force = true;
+ prefer_specific = true;
+ };
+
+ fetchart = {
+ cautious = true;
+ sources = "filesystem coverart itunes amazon lastfm wikipedia";
+ };
+ };
+ };
+}
diff --git a/home/profiles/ssh.nix b/home/profiles/ssh.nix
new file mode 100644
index 0000000..576f451
--- /dev/null
+++ b/home/profiles/ssh.nix
@@ -0,0 +1,18 @@
+{ ... }:
+{
+ programs.ssh = {
+ enable = true;
+ forwardAgent = true;
+ serverAliveInterval = 60;
+ controlMaster = "auto";
+ controlPersist = "30m";
+ matchBlocks = {
+ "github.com" = {
+ hostname = "github.com";
+ user = "git";
+ forwardAgent = false;
+ extraOptions = { preferredAuthentications = "publickey"; };
+ };
+ };
+ };
+}
diff --git a/home/profiles/sway.nix b/home/profiles/sway.nix
new file mode 100644
index 0000000..0665556
--- /dev/null
+++ b/home/profiles/sway.nix
@@ -0,0 +1,172 @@
+{ config, lib, pkgs, ... }:
+let
+ modifier = "Mod4"; # `Super` key
+in
+{
+ imports = [
+ ./gtk.nix
+ ./mako.nix
+ ./waybar.nix
+ ./wofi.nix
+ ];
+
+ home.packages = with pkgs; [
+ wlogout
+ brightnessctl
+ pulseaudio
+ grim
+ slurp
+ polkit_gnome
+ xsettingsd
+ swaylock
+ swayidle
+ wl-clipboard
+ ];
+
+ home.sessionVariables = {
+ MOZ_ENABLE_WAYLAND = "1";
+ XDG_CURRENT_DESKTOP = "sway";
+ XDG_SESSION_TYPE = "wayland";
+ };
+
+ programs = {
+ zsh.loginExtra = ''
+ if [ $(ps ax | grep "[s]sh-agent" | wc -l) -eq 0 ] ; then
+ eval $(ssh-agent -s) > /dev/null
+ fi
+ if [ "$(tty)" = "/dev/tty1" ]; then
+ exec sway &> /dev/null
+ fi
+ '';
+
+ zsh.profileExtra = ''
+ if [ $(ps ax | grep "[s]sh-agent" | wc -l) -eq 0 ] ; then
+ eval $(ssh-agent -s) > /dev/null
+ fi
+ if [ "$(tty)" = "/dev/tty1" ]; then
+ exec sway &> /dev/null
+ fi
+ '';
+ };
+
+ wayland.windowManager.sway = {
+ enable = true;
+ # in order to import some variables (e.g. PATH) so that all the
+ # units that will be started have all the required environment
+ # variables
+ extraSessionCommands = "systemctl --user import-environment";
+ # this will start sway-session.target and run
+ # dbus-update-activation-environment
+ systemdIntegration = true;
+ config = {
+ # FIXME: this should be a variable
+ terminal = "alacritty";
+ modifier = modifier;
+ menu = ''${pkgs.wofi}/bin/wofi -S drun -p "app:" -L 10'';
+ bars = [ ];
+ fonts = {
+ names = [ "Source Code Pro" ];
+ size = 10.0;
+ };
+ keybindings = lib.mkOptionDefault {
+ # control the volume
+ "XF86AudioRaiseVolume" =
+ "exec ${pkgs.pulseaudio}/bin/pactl set-sink-volume @DEFAULT_SINK@ +5%";
+ "XF86AudioLowerVolume" =
+ "exec ${pkgs.pulseaudio}/bin/pactl set-sink-volume @DEFAULT_SINK@ -5%";
+ "XF86AudioMute" =
+ "exec ${pkgs.pulseaudio}/bin/pactl set-sink-mute @DEFAULT_SINK@ toggle";
+ "XF86AudioMicMute" =
+ "exec ${pkgs.pulseaudio}/bin/pactl set-source-mute @DEFAULT_SOURCE@ toggle";
+
+ # control brightness
+ "XF86MonBrightnessDown" =
+ "exec ${pkgs.brightnessctl}/bin/brightnessctl set 5%-";
+ "XF86MonBrightnessUp" =
+ "exec ${pkgs.brightnessctl}/bin/brightnessctl set +5%";
+
+ # logout
+ "${modifier}+Escape" = "exec ${pkgs.wlogout}/bin/wlogout";
+
+ # screenshot
+ "${modifier}+s" =
+ "exec ${pkgs.grim}/bin/grim $(xdg-user-dir DOCUMENTS)/screenshots/$(date +'%Y-%m-%d-%H%M%S_screenshot.png')";
+ "${modifier}+Shift+s" =
+ "exec ${pkgs.slurp}/bin/slurp | ${pkgs.grim}/bin/grim -g - $(xdg-user-dir DOCUMENTS)/screenshots/$(date +'%Y-%m-%d-%H%M%S_screenshot.png')";
+
+ # File Manager
+ "${modifier}+p" = "exec ${pkgs.pcmanfm}/bin/pcmanfm";
+ };
+
+ # use `swaymsg -t get_tree' to get the title/name/ID of the applications
+ window = {
+ commands = [
+ {
+ criteria.class = ".blueman-manager-wrapped";
+ command = "floating enable";
+ }
+ {
+ criteria.class = "Pavucontrol";
+ command = "floating enable";
+ }
+ ];
+ };
+
+ input = {
+ "*" = {
+ "xkb_layout" = "us,fr";
+ # map capslock to ctrl, and switch layout using shift+caps
+ "xkb_options" = "ctrl:nocaps,grp:shift_caps_toggle";
+ };
+ };
+
+ assigns = {
+ "1" = [{ app_id = "emacs"; }];
+ "2" = [{ app_id = "Alacritty"; }];
+ "3" = [{ app_id = "firefox"; }];
+ "4" = [{ app_id = "org.gnome.Fractal"; }];
+ };
+
+ output = {
+ "*" = {
+ scale = "1.5";
+ bg = "#2E3440 solid_color";
+ };
+ # This is for aptos
+ "eDP-1" = { scale = "1.3"; };
+ };
+ };
+ };
+
+ xdg.configFile."swaylock/config".source = pkgs.writeText "config" ''
+ color=2E3440
+ daemonize
+ indicator-caps-lock
+ hide-keyboard-layout
+ '';
+
+ services.swayidle = {
+ enable = true;
+ events = [
+ {
+ event = "before-sleep";
+ command = "${pkgs.swaylock}/bin/swaylock -fF";
+ }
+ {
+ event = "lock";
+ command = "${pkgs.swaylock}/bin/swaylock -fF";
+ }
+ ];
+ timeouts = [
+ {
+ timeout = 300;
+ command = "${pkgs.sway}/bin/swaymsg \"output * dpms off\"";
+ resumeCommand = "${pkgs.sway}/bin/swaymsg \"output * dpms on\"";
+ }
+ {
+ timeout = 310;
+ command = "${pkgs.systemd}/bin/loginctl lock-session";
+ }
+ ];
+ };
+}
diff --git a/home/profiles/tmux.nix b/home/profiles/tmux.nix
new file mode 100644
index 0000000..22f8683
--- /dev/null
+++ b/home/profiles/tmux.nix
@@ -0,0 +1,20 @@
+{ ... }:
+{
+ programs.tmux = {
+ enable = true;
+
+ terminal = "xterm-256color";
+ escapeTime = 0;
+ aggressiveResize = true;
+ baseIndex = 1;
+ shortcut = "z";
+ clock24 = true;
+ historyLimit = 50000; # Bigger buffer
+
+ extraConfig = ''
+ setw -g mouse on
+
+ set-option -g renumber-windows on
+ '';
+ };
+}
diff --git a/home/profiles/waybar.nix b/home/profiles/waybar.nix
new file mode 100644
index 0000000..e6f6c3d
--- /dev/null
+++ b/home/profiles/waybar.nix
@@ -0,0 +1,155 @@
+{ config, lib, pkgs, ... }:
+let
+ # waybar-systemd = pkgs.writeShellApplication {
+ # name = "waybar-systemd.sh";
+ # runtimeInputs = [ ];
+ # text = ''
+ # failed_user="$(systemctl --plain --no-legend --user list-units --state=failed | awk '{ print $1 }')"
+ # failed_system="$(systemctl --plain --no-legend list-units --state=failed | awk '{ print $1 }')"
+
+ # failed_systemd_count="$(echo -n "$failed_system" | grep -c '^')"
+ # failed_user_count="$(echo -n "$failed_user" | grep -c '^')"
+
+ # text=$(( failed_systemd_count + failed_user_count ))
+
+ # if [ "$text" -eq 0 ]; then
+ # printf '{"text": ""}\n'
+ # else
+ # tooltip=""
+
+ # [ -n "$failed_system" ] && tooltip="Failed system services:\n\n${failed_system}\n\n${tooltip}"
+ # [ -n "$failed_user" ] && tooltip="Failed user services:\n\n${failed_user}\n\n${tooltip}"
+
+ # tooltip="$(printf "%s" "$tooltip" | perl -pe 's/\n/\\n/g' | perl -pe 's/(?:\\n)+$//')"
+
+ # printf '{"text": "%s", "tooltip": "%s" }\n' "$text" "$tooltip"
+ # fi
+ # '';
+ # };
+in
+{
+ programs.waybar = {
+ enable = true;
+ systemd.enable = true;
+
+ settings = [{
+ layer = "bottom";
+ height = 25;
+ position = "top";
+ margin-top = 0;
+ margin-left = 0;
+ margin-right = 0;
+ margin-bottom = 0;
+ modules-left = [ "sway/workspaces" "sway/mode" ];
+ modules-right = [ "pulseaudio" "network" "battery" "clock" "tray" ];
+ "sway/workspaces" = {
+ format = "{name}";
+ disable-scroll = true;
+ };
+ "sway/mode" = { format = "{}"; };
+ tray = { spacing = 10; };
+ clock = { format = "{: %a %b %d %R}"; };
+ battery = {
+ states = {
+ warning = 30;
+ critical = 15;
+ };
+ format = "ac:{capacity}%";
+ tooltip = true;
+ tooltip-format = "{timeTo} ({capacity}%)";
+ };
+ # "custom/systemd" = {
+ # exec = "${waybarSystemd}/bin/waybar-systemd";
+ # return-type = "json";
+ # interval = 10;
+ # };
+ pulseaudio = {
+ format = "vol:{volume}%";
+ format-bluetooth = "bt:{volume}%";
+ format-bluetooth-muted = "bt:{volume}%";
+ format-muted = "vol:{volume}%";
+ on-click = "pavucontrol";
+ };
+ "network" = {
+ format-wifi = "{essid}:{signalStrength}%";
+ format-ethernet = "{ipaddr}/{cidr}";
+ format-linked = "{ifname} (No IP)";
+ format-disconnected = "network unavailable";
+ format-alt = "{ifname}: {ipaddr}/{cidr}";
+ tooltip = false;
+ };
+ }];
+ };
+
+ programs.waybar.style = pkgs.writeText "style.css" ''
+ * {
+ border-radius: 0;
+ border: none;
+ margin: 0;
+ min-height: 0;
+ padding: 0;
+ font-family: Source Code Pro;
+ font-size: 15px;
+ }
+ window#waybar {
+ background-color: #282A36;
+ color: #eee;
+ }
+ #workspaces button {
+ padding: 0 3px;
+ background-color: transparent;
+ color: #eee;
+ }
+ #workspaces button.focused {
+ background-color: #285577;
+ border: 1px solid #4c7899;
+ }
+ #clock,
+ #battery,
+ #network,
+ #pulseaudio,
+ #tray,
+ #mode {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+ #mode {
+ /* No styles */
+ }
+ #tray {
+ /* No styles */
+ }
+ #clock {
+ /* No styles */
+ }
+ #battery {
+ animation-timing-function: linear;
+ animation-iteration-count: infinite;
+ animation-direction: alternate;
+ }
+ #battery.discharging {
+ color: #90a1ad;
+ }
+ #battery.charging {
+ color: #fffff8;
+ }
+ #battery.warning {
+ border-bottom: 2px solid #ff9e21;
+ }
+ #battery.critical {
+ border-bottom: 2px solid #ff3121;
+ }
+ #network {
+ /* No styles */
+ }
+ #network.disconnected {
+ color: orange;
+ }
+ #pulseaudio {
+ /* No styles */
+ }
+ #pulseaudio.muted {
+ color: #90a1ad;
+ }
+ '';
+}
diff --git a/home/profiles/wofi.nix b/home/profiles/wofi.nix
new file mode 100644
index 0000000..7140650
--- /dev/null
+++ b/home/profiles/wofi.nix
@@ -0,0 +1,13 @@
+{ config, lib, pkgs, ... }: {
+
+ home.packages = with pkgs; [ wofi ];
+
+ xdg.configFile."wofi/config".source = pkgs.writeText "config" ''
+ allow_images=true
+ image_size=25px
+ drun-display_generic=true
+ dynamic_lines=true
+ insensitive=true
+ run-cache_file=/dev/null
+ '';
+}
diff --git a/home/profiles/workstation.nix b/home/profiles/workstation.nix
new file mode 100644
index 0000000..acbbccb
--- /dev/null
+++ b/home/profiles/workstation.nix
@@ -0,0 +1,113 @@
+{ config, lib, pkgs, ... }:
+let
+ restic-nas = pkgs.writeShellApplication
+ {
+ name = "restic-nas";
+ runtimeInputs = [ pkgs.restic pkgs.tailscale pkgs.jq ];
+ text = ''
+ NAS=$(tailscale status --json | jq -r '.Peer | map(select(.HostName == "tahoe"))[0].TailscaleIPs[0]')
+
+ RESTIC_REPOSITORY="sftp:''${NAS}:/$(hostname)"
+ export RESTIC_REPOSITORY
+ export RESTIC_PASSWORD_FILE=/run/agenix/restic/repo-users
+
+ sudo -E restic -o sftp.command="ssh backup@''${NAS} -i /run/agenix/restic/ssh-key -s sftp" "$@"
+ '';
+ };
+
+ album-to-nas = pkgs.writeShellApplication {
+ name = "album-to-nas";
+ runtimeInputs = [ pkgs.jq pkgs.tailscale ];
+ text = ''
+ ALBUM_PATH="$1"
+
+ NAS=$(tailscale status --json | jq -r '.Peer | map(select(.HostName == "tahoe"))[0].TailscaleIPs[0]')
+
+ scp "$ALBUM_PATH" "$NAS:~/import/album.zip"
+ ssh "$NAS" bc-to-beet ~/import/album.zip
+ '';
+ };
+in
+{
+ imports = [
+ ./alacritty.nix
+ ./dev.nix
+ ./emacs.nix
+ ./firefox.nix
+ ./tmux.nix
+ ./yubikey.nix
+ ./ytdlp.nix
+ ];
+
+ home.packages = with pkgs; [
+ # media
+ gnome3.eog
+ gnome3.evince
+ sublime-music
+ vlc
+ yt-dlp
+
+ passage
+ tree
+
+ # scanning
+ tesseract
+ imagemagick
+ exiftool
+ sane-airscan
+
+ transmission-remote-gtk
+
+ # custom tools
+ album-to-nas
+ restic-nas
+
+ # tools from external repositories
+ # x509-info
+ # gh-ssh-keys
+ # masked-emails
+ ];
+
+ programs.feh.enable = true;
+ programs.mpv = {
+ enable = true;
+ config = {
+ sub-auto = "fuzzy";
+ vo = "gpu";
+ hwdec = "auto-safe";
+ gpu-context = "wayland";
+ audio-display = "no";
+ cache-pause = "no";
+ cache = "yes";
+ mute = "no";
+ osc = "yes";
+ screenshot-directory = "~/documents/screenshots/mpv-screenshots/";
+ screenshot-format = "png";
+ };
+ scripts = lib.attrVals [ "sponsorblock" ] pkgs.mpvScripts;
+ };
+
+ services.gammastep = {
+ enable = true;
+ #TODO: this needs to come from locale.nix
+ latitude = 37.8715;
+ longitude = -122.273;
+ temperature = {
+ day = 5000;
+ night = 3700;
+ };
+ };
+
+ home.sessionVariables = {
+ PASSAGE_DIR = "${config.xdg.dataHome}/passage/store";
+ PASSAGE_IDENTITIES_FILE = "${config.xdg.dataHome}/passage/identities";
+ # for now I have to default to rage, as the version of age is
+ # not recent enough to work with keys generated by
+ # age-plugin-yubikey
+ PASSAGE_AGE = "${pkgs.rage}/bin/rage";
+ };
+
+
+ # enable bluetooth
+ services.blueman-applet.enable = true;
+}
diff --git a/home/profiles/ytdlp.nix b/home/profiles/ytdlp.nix
new file mode 100644
index 0000000..ce2e32c
--- /dev/null
+++ b/home/profiles/ytdlp.nix
@@ -0,0 +1,37 @@
+{ pkgs, ... }:
+{
+ home.packages = with pkgs; [
+ yt-dlp
+ ];
+
+ xdg.configFile."yt-dlp/config".source = pkgs.writeText "config" ''
+ # Preferred formats:
+ # 1. 1080p, combined, mp4 (for some non-youtube sites).
+ # 2. 1080p, combined, any format (in case mp4 is not available).
+ # 3. 1080p, best video + best audio (only available with separate video and audio on youtube).
+ # 4. >30fps (any resolution), best video + best audio (only available with separate video and audio on youtube).
+ # 5. 720p, pre-joined, because it is available on youtube.
+ # 6. <720p, best video + best audio (480p and some other lower resolutions are only available with separate video and audio on youtube).
+ # 7. When all else fails, take whatever youtube-dl thinks is the best (mainly for non-YT websites).
+ --format="best[height=1080][ext=mp4]/best[height=1080]/bestvideo[height=1080][ext=mp4]+bestaudio[ext=m4a]/bestvideo[fps>30][ext=mp4]+bestaudio[ext=m4a]/best[height=720][ext=mp4]/bestvideo[ext=mp4]+bestaudio[ext=m4a]/best"
+
+ --continue
+
+ --sub-langs all
+ --write-subs
+
+ --convert-subs=srt
+
+ --restrict-filenames
+ --output="$HOME/media/videos/%(uploader)s/%(playlist)s/%(upload_date)s-%(title)s.%(ext)s"
+ --merge-output-format mkv
+
+ --embed-metadata
+ --embed-chapters
+ --embed-info-json
+ # create chapter entries to mark sponsor segments
+ --sponsorblock-mark all
+
+ --yes-playlist
+ '';
+}
diff --git a/home/profiles/yubikey.nix b/home/profiles/yubikey.nix
new file mode 100644
index 0000000..b18ce5d
--- /dev/null
+++ b/home/profiles/yubikey.nix
@@ -0,0 +1,28 @@
+{ pkgs, lib, config, ... }:
+{
+ home.packages = with pkgs; [ yubikey-manager yubikey-touch-detector ];
+
+ systemd.user.sockets.yubikey-touch-detector = {
+ Unit.Description = "Unix socket activation for YubiKey touch detector service";
+ Socket = {
+ ListenStream = "%t/yubikey-touch-detector.socket";
+ RemoveOnStop = true;
+ };
+ Install.WantedBy = [ "sockets.target" ];
+ };
+
+ systemd.user.services.yubikey-touch-detector = {
+ Unit = {
+ Description = "Detects when your YubiKey is waiting for a touch";
+ Requires = "yubikey-touch-detector.socket";
+ };
+ Service = {
+ ExecStart = "${pkgs.yubikey-touch-detector}/bin/yubikey-touch-detector --libnotify";
+ EnvironmentFile = "-%E/yubikey-touch-detector/service.conf";
+ };
+ Install = {
+ Also = "yubikey-touch-detector.socket";
+ WantedBy = [ "default.target" ];
+ };
+ };
+}
diff --git a/home/profiles/zsh/completion-style.zsh b/home/profiles/zsh/completion-style.zsh
new file mode 100644
index 0000000..79a4e68
--- /dev/null
+++ b/home/profiles/zsh/completion-style.zsh
@@ -0,0 +1,42 @@
+# 'ctrl-x r' will complete the 12 last modified (mtime) files/directories
+zle -C newest-files menu-complete _generic
+# Use "*newest-files" so that it matches both "newest-files" and
+# "load-completion-and-newest-files".
+zstyle ':completion:*newest-files:*' completer _files
+zstyle ':completion:*newest-files:*' file-patterns '*(omN[1,12])'
+zstyle ':completion:*newest-files:*' menu select yes
+zstyle ':completion:*newest-files:*' sort false
+zstyle ':completion:*newest-files:*' matcher-list 'b:=*' # important
+
+# colors for zsh file name completion
+zmodload zsh/complist
+zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}
+
+# Show a prompt on selection
+zstyle ':completion:*' select-prompt '%SScrolling active: current selection at %p%s'
+
+# Use arrow keys in completion list
+zstyle ':completion:*' menu select
+
+# Group results by category
+zstyle ':completion:*' group-name ''
+
+# Keep directories and files separated
+zstyle ':completion:*' list-dirs-first true
+
+# match uppercase from lowercase
+zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
+
+# Filename suffixes to ignore during completion (except after rm command)
+zstyle ':completion:*:*:(^rm):*:*files' ignored-patterns '*?.old'
+
+# command for process lists, the local web server details and host completion
+# on processes completion complete all user processes
+zstyle ':completion:*:processes' command 'ps -au$USER'
+
+# Completion formatting and messages
+zstyle ':completion:*' verbose yes
+zstyle ':completion:*:descriptions' format '%B%d%b'
+zstyle ':completion:*:messages' format '%d'
+zstyle ':completion:*:warnings' format 'No matches for: %d'
+zstyle ':completion:*:corrections' format '%B%d (errors: %e)%b'
diff --git a/home/profiles/zsh/default.nix b/home/profiles/zsh/default.nix
new file mode 100644
index 0000000..38450ab
--- /dev/null
+++ b/home/profiles/zsh/default.nix
@@ -0,0 +1,51 @@
+{ config, pkgs, lib, ... }:
+{
+ home.packages = with pkgs; [ zsh-completions ];
+
+ programs.zsh = {
+ enable = true;
+ dotDir = ".config/zsh";
+
+ enableCompletion = true;
+ enableAutosuggestions = true;
+
+ history = {
+ size = 500000;
+ save = 500000;
+ extended = false;
+ ignoreSpace = true;
+ ignoreDups = true;
+ share = false;
+ # see
+ # https://github.com/nix-community/home-manager/blob/32a7da69dc53c9eb5ad0675eb7fdc58f7fe35272/modules/programs/zsh.nix#L537
+ path = "${config.xdg.dataHome}/zsh/zsh_history";
+ };
+
+ localVariables = {
+ # Print timing statistics for everything which takes longer than 5 seconds of
+ # user + system time.
+ REPORTTIME = 5;
+ };
+
+ shellAliases = {
+ ll = "ls -l --color=auto";
+ lt = "ls -ltrh --color=auto";
+ la = "ls -ltrha --color=auto";
+ pkgsearch = "nix search nixpkgs";
+ hms = "home-manager switch --flake .";
+ nr = "sudo nixos-rebuild switch --flake .";
+ flup = "nix flake update --commit-lock-file";
+ dhcp-leasese = "xdg-open http://192.168.6.1:8067/";
+ };
+
+ defaultKeymap = "emacs";
+
+ initExtra = lib.concatMapStrings builtins.readFile [
+ ./completion-style.zsh
+ ./options.zsh
+ ./prompt.zsh
+ ./tmux.zsh
+ ./new-go-project.zsh
+ ];
+ };
+}
diff --git a/home/profiles/zsh/new-go-project.zsh b/home/profiles/zsh/new-go-project.zsh
new file mode 100644
index 0000000..0b96a34
--- /dev/null
+++ b/home/profiles/zsh/new-go-project.zsh
@@ -0,0 +1,19 @@
+new-go-project() {
+ local project_name=$1
+
+ echo "> creating ${project_name}"
+ cd ~/workspace/
+ mkdir $project_name
+ cd $project_name
+
+ echo "> initializing the git repository"
+ git init .
+
+ echo "> setting the default template for go projects"
+ nix flake init -t ~/workspace/world/templates#go
+ direnv allow
+
+ echo "> creating initial commit, touch your yubikey"
+ git add .
+ git commit -m 'initial commit'
+}
diff --git a/home/profiles/zsh/options.zsh b/home/profiles/zsh/options.zsh
new file mode 100644
index 0000000..6d39bc1
--- /dev/null
+++ b/home/profiles/zsh/options.zsh
@@ -0,0 +1,27 @@
+# Show an error when a globbing expansion doesn't find any match
+setopt nomatch
+
+# List on ambiguous completion and Insert first match immediately
+setopt autolist menucomplete
+
+# Use pushd when cd-ing around
+setopt autopushd pushdminus pushdsilent
+
+# Use single quotes in string without the weird escape tricks
+setopt rcquotes
+
+# Single word commands can resume an existing job
+setopt autoresume
+
+# Append commands to history as they are exectuted
+setopt inc_append_history_time
+
+# Remove useless whitespace from commands
+setopt hist_reduce_blanks
+
+# Those options aren't wanted
+unsetopt beep extendedglob notify
+
+# word select works like in bash
+autoload -U select-word-style
+select-word-style bash
diff --git a/home/profiles/zsh/prompt.zsh b/home/profiles/zsh/prompt.zsh
new file mode 100644
index 0000000..8a3efa9
--- /dev/null
+++ b/home/profiles/zsh/prompt.zsh
@@ -0,0 +1,17 @@
+setopt prompt_subst
+
+autoload -Uz vcs_info
+
+# display the name of the branch
+zstyle ':vcs_info:git*' formats " [%b]"
+zstyle ':vcs_info:*' enable git
+
+precmd () { vcs_info }
+PROMPT='%m%f:%F{green}%~%f%F{yellow}$vcs_info_msg_0_ %F{reset}'
+
+# For tramp (emacs).
+if [ "$TERM" = "dumb" ]; then
+ unset PROMPT
+ PS1='$ '
+ unsetopt zle
+fi
diff --git a/home/profiles/zsh/tmux.zsh b/home/profiles/zsh/tmux.zsh
new file mode 100644
index 0000000..97944f5
--- /dev/null
+++ b/home/profiles/zsh/tmux.zsh
@@ -0,0 +1,9 @@
+# If we're not in an ssh connection, and tmux is installed, and we're
+# not already in a tmux session, attach to the session named
+# 'default', and if the session does not exist, start one named
+# 'default'
+if [ -z "$SSH_CONNECTION" ]; then
+ if command -v tmux &> /dev/null && [ -z "$TMUX" ]; then
+ tmux attach -t default || tmux new -s default
+ fi
+fi