{ config, lib, pkgs, ... }: let git-diff-image = pkgs.callPackage ../packages/git-diff-image.nix { }; iosevkaCommon = { widths = { normal = { css = "normal"; menu = 5; shape = 500; }; }; weights = { regular = { css = 400; menu = 400; shape = 400; }; bold = { css = 700; menu = 700; shape = 800; }; }; slopes = { upright = { angle = 0; css = "normal"; menu = "upright"; shape = "upright"; }; italic = { angle = 9.4; css = "italic"; menu = "italic"; shape = "italic"; }; }; variants.design = { digit-form = "old-style"; capital-a = "curly-serifless"; capital-g = "toothless-corner-serifless-hooked"; capital-k = "curly-serifless"; capital-u = "toothless-corner"; capital-r = "standing"; capital-v = "curly"; capital-w = "curly"; capital-x = "curly-serifless"; capital-y = "curly-serifless"; capital-z = "curly-serifless"; a = "double-storey-toothless-corner"; b = "toothless-corner"; d = "toothless-corner-serifless"; f = "flat-hook-crossbar-at-x-height"; g = "earless-corner"; i = "serifed-flat-tailed"; j = "flat-hook-serifed"; l = "flat-tailed"; m = "earless-corner-double-arch-short-leg"; n = "earless-corner-straight"; p = "earless-corner"; q = "earless-corner"; r = "earless-corner"; t = "flat-hook-short-neck2"; u = "toothless-corner"; w = "curly"; x = "curly-serifless"; y = "curly"; z = "curly-serifless"; zero = "slashed"; two = "straight-neck"; three = "flat-top"; four = "semi-open-non-crossing"; five = "oblique-upper-left-bar"; six = "straight-bar"; seven = "bend-serifless"; eight = "crossing-asymmetric"; nine = "straight-bar"; tilde = "low"; asterisk = "hex-low"; underscore = "above-baseline"; caret = "low"; brace = "curly"; at = "short"; dollar = "open-cap"; cent = "open"; percent = "dots"; bar = "force-upright"; }; }; iosevka-custom-proportional = pkgs.iosevka.override { set = "custom-proportional"; privateBuildPlan = iosevkaCommon // { family = "Iosevka Custom Proportional"; spacing = "quasi-proportional"; ligations = { inherits = "javascript"; }; }; }; iosevka-custom-mono = pkgs.iosevka.override { set = "custom-mono"; privateBuildPlan = iosevkaCommon // { family = "Iosevka Custom Mono"; ligations = { inherits = "javascript"; }; }; }; iosevka-custom-term = pkgs.iosevka.override { set = "custom-term"; privateBuildPlan = iosevkaCommon // { family = "Iosevka Custom Term"; spacing = "term"; no-ligation = true; }; }; mozjpeg-simple = pkgs.writeShellScriptBin "mozjpeg" (with pkgs; '' set -Eeuo pipefail input="$1" shift mime="$(${file}/bin/file --brief --mime "$input")" output="''${input%.*}.jpg" if [[ "$mime" == 'image/heic'* ]]; then png="$(mktemp --suffix=.png)"; trap 'rm -f "$png"' EXIT ${libheif}/bin/heif-convert "$input" "$png" input="png:$png" fi ${imagemagick}/bin/convert -flatten "$input" ppm:- \ | ${mozjpeg}/bin/cjpeg -optimize -quality 90 "$@" \ > "$output" ''); palette = import ./palette.nix; in { imports = [ ./local/home.nix ]; # Home manager programs.home-manager.enable = true; nixpkgs.config.allowUnfree = true; manual.html.enable = true; home.username = "ak"; home.homeDirectory = "/home/ak"; # Applications home.packages = with pkgs; [ darktable delta dnsutils exiftool fd file firefox-wayland gimp-with-plugins git-diff-image git-filter-repo gnome.gnome-tweaks gnomeExtensions.system-monitor gnomeExtensions.tray-icons-reloaded gnupg google-fonts # If removed, add `roboto` gopass htop httpie imagemagick inkscape iosevka-custom-mono iosevka-custom-proportional iosevka-custom-term killall lsof moreutils mozjpeg-simple mtr multitail ncdu nix-top nix-tree nixpkgs-fmt pwgen ripgrep rsync shellcheck tig trash-cli v4l-utils whois xorg.xev yaru-theme (writeShellScriptBin "add-words" '' set -Eeuo pipefail cd "/home/ak/src/configuration" message='Update spell check word list' txt='common/words.txt' if [[ -n "$(${git}/bin/git status --porcelain "$txt")" ]]; then echo "Error: Existing uncommitted changes to $txt" >&2 exit 1 fi if [[ -n "$(${git}/bin/git diff --cached --name-only)" ]]; then echo "Error: Existing staged changes" >&2 exit 1 fi printf '%s\n' "$@" | sort "$txt" - | uniq | ${moreutils}/bin/sponge "$txt" ${git}/bin/git add "$txt" if [[ "$(${git}/bin/git log -1 --pretty='%s')" == "$message" ]] && ! ${git}/bin/git merge-base --is-ancestor 'HEAD' '@{u}'; then ${git}/bin/git commit --amend --no-edit else ${git}/bin/git commit --message "$message" fi ${git}/bin/git show HEAD '') (writeShellScriptBin "off" '' set -Eeuxo pipefail # Containers podman system prune --force --volumes docker system prune --force --volumes # Channels sudo nix-channel --update nix-channel --update # User home-manager expire-generations '-7 days' home-manager switch # System sudo nixos-rebuild boot sudo poweroff '') ]; fonts.fontconfig.enable = true; programs = { bat.enable = true; direnv = { enable = true; nix-direnv.enable = true; stdlib = with pkgs; '' _gopass_await() { ${gopass}/bin/gopass show "$@" 2>( \ ${gnome.zenity}/bin/zenity --progress --auto-close --no-cancel --pulsate \ --title 'Please tap the hardware key' \ --text "gopass show $*" \ ) } use_gopass() { eval "$(_gopass_await "$@")" } ''; }; exa = { enable = true; enableAliases = true; }; fzf = rec { enable = true; enableZshIntegration = true; defaultOptions = [ "--height 33%" "--reverse" ]; defaultCommand = "fd --one-file-system --type file"; # --no-ignore-parent pending https://github.com/sharkdp/fd/pull/817 (fd v9) fileWidgetCommand = defaultCommand; changeDirWidgetCommand = "fd --one-file-system --type directory"; # --no-ignore-parent pending https://github.com/sharkdp/fd/pull/817 (fd v9) }; git = { enable = true; aliases = { ff = "merge --ff-only"; diff-image = "!f() { cd -- \"\${GIT_PREFIX:-.}\"; GIT_DIFF_IMAGE_ENABLED=1 git diff \"$@\"; }; f"; kitty = "difftool --tool=kitty --no-symlinks --dir-diff"; puff = "pull --ff-only"; recent = "!git --no-pager log --max-count 8 --pretty=tformat:\"%w($(tput cols),0,8)%C(cyan)%h%Creset %C(yellow)%cr:%C(magenta)%d%Creset %s\""; }; attributes = [ "*.gif diff=image" "*.jpg diff=image" "*.png diff=image" ]; delta = { enable = true; options = { file-renamed-label = "moved:"; line-numbers-left-format = "{nm:>1} "; line-numbers-left-style = "#444444"; line-numbers-minus-style = "#872843 bold"; line-numbers-plus-style = "#5c7b2a bold"; line-numbers-right-format = "{np:>1}▐"; line-numbers-right-style = "#444444"; line-numbers-zero-style = "#444444 bold"; minus-emph-style = "#827c7d #42282d"; minus-empty-line-marker-style = "normal #42282d"; minus-non-emph-style = "#444444"; minus-style = "#827c7d #42282d"; plus-emph-style = "syntax #343e28"; plus-empty-line-marker-style = "normal #343e28"; plus-non-emph-style = "syntax"; plus-style = "syntax #343e28"; syntax-theme = "Monokai Extended"; whitespace-error-style = "reverse white"; full = { file-style = "white bold"; file-decoration-style = "omit"; hunk-header-style = "omit"; line-numbers = true; }; }; }; signing.key = "0x9254D45940949194"; extraConfig = { core.autocrlf = "input"; diff.algorithm = "patience"; init.defaultBranch = "main"; merge.commit = false; push.followTags = true; diff.image.command = "${git-diff-image}/bin/git_diff_image"; difftool = { prompt = false; trustExitCode = true; }; "difftool \"kitty\"".cmd = "kitty +kitten diff $LOCAL $REMOTE"; tig = { line-graphics = "utf-8"; main-view-date = "custom"; main-view-date-format = "%F %H:%M"; main-view-id-display = true; show-changes = false; tab-size = 4; truncation-delimiter = "utf-8"; vertical-split = false; color = { author = "color8 default"; cursor = "black magenta bold"; graph-commit = "magenta default"; date = "yellow default"; id = "cyan default"; main-head = "magenta default bold"; main-local-tag = "green default"; main-ref = "magenta default"; main-remote = "blue default"; main-tag = "green default"; main-tracked = "blue default bold"; palette-0 = "color8 default"; palette-1 = "color8 default"; palette-2 = "color8 default"; palette-3 = "color8 default"; palette-4 = "color8 default"; palette-5 = "color8 default"; palette-6 = "color8 default"; palette-7 = "color8 default"; palette-8 = "color8 default"; palette-9 = "color8 default"; palette-10 = "color8 default"; palette-11 = "color8 default"; palette-12 = "color8 default"; palette-13 = "color8 default"; search-result = "black white bold"; title-blur = "white black"; title-focus = "white black bold"; }; }; }; ignores = [ ".direnv/" ".envrc" ".envrc.gemset.nix" ".envrc.nix" ".vscode/" ]; iniContent.core.pager = lib.mkForce "${pkgs.delta}/bin/delta --color-only --features full"; # Set feature userName = "Andrew Kvalheim"; userEmail = "Andrew@Kvalhe.im"; }; jq.enable = true; kitty = { enable = true; font = { package = iosevka-custom-term; name = "Iosevka Custom Term"; size = 11; }; keybindings = { "shift+left" = "previous_tab"; "ctrl+shift+left" = "move_tab_backward"; "shift+right" = "next_tab"; "ctrl+shift+right" = "move_tab_forward"; "shift+down" = "previous_window"; "ctrl+shift+up" = "move_window_backward"; "shift+up" = "next_window"; "ctrl+shift+down" = "move_window_forward"; "alt+down" = "resize_window shorter"; "alt+up" = "resize_window taller"; }; settings = with palette; { # Mouse click_interval = "0.25"; focus_follows_mouse = "yes"; mouse_hide_wait = "0"; select_by_word_characters = "-_?&%+#"; # Windows hide_window_decorations = true; scrollback_lines = "16384"; enabled_layouts = "vertical, horizontal"; # Workaround for https://github.com/kovidgoyal/kitty/issues/3180 touch_scroll_multiplier = "10"; # Sounds enable_audio_bell = "no"; # Font bold_font = "Iosevka Custom Term Bold"; italic_font = "Iosevka Custom Term Italic"; bold_italic_font = "Iosevka Custom Term Bold Italic"; active_tab_font_style = "bold"; inactive_tab_font_style = "bold"; # Cursor cursor_shape = "beam"; # URLs url_style = "single"; # Colors wayland_titlebar_color = black; foreground = white; background = black; cursor = orange; url_color = white; active_border_color = dark-gray; inactive_border_color = dark-gray; bell_border_color = red; active_tab_foreground = white; active_tab_background = dark-gray; inactive_tab_foreground = gray; inactive_tab_background = dark-gray; selection_foreground = black; selection_background = orange; color0 = dark-gray; color1 = red; color2 = green; color3 = yellow; color4 = blue; color5 = orange; color6 = purple; color7 = white; color8 = gray; color9 = red; color10 = green; color11 = yellow; color12 = blue; color13 = orange; color14 = purple; color15 = white; }; }; nix-index.enable = true; ssh = { enable = true; extraOptionOverrides = { GSSAPIAuthentication = "no"; PreferredAuthentications = "publickey"; }; }; vscode = { enable = true; package = pkgs.vscodium; userSettings = import ./vscode.nix { inherit lib; }; keybindings = [ { key = "ctrl+j"; command = "-workbench.action.togglePanel"; } { key = "ctrl+j"; command = "editor.action.joinLines"; } { key = "shift+alt+m"; command = "editor.emmet.action.wrapWithAbbreviation"; } ]; }; zsh = { enable = true; autocd = false; history = { expireDuplicatesFirst = true; extended = true; ignoreDups = false; ignoreSpace = true; save = 100000000; size = 1000000000; }; sessionVariables = { HIST_STAMPS = "yyyy-mm-dd"; REPORTTIME = 10; WORDCHARS = "_.~;!#$%^"; }; initExtra = '' setopt HIST_FIND_NO_DUPS setopt NOCLOBBER setopt PUSHD_SILENT export DIRENV_LOG_FORMAT="$(print -P "%B%F{8}┃ %%s%f")" TIMEFMT="$(print -P "%B%F{8}┃ Duration: %%*Es, CPU: %%P, Memory: %%MkB%f")" git() { if [[ "$1" == 'clone' && "$2" =~ '^https://(github\.com|gitlab\.com)/([^/]+)/[^/]+' ]]; then shift echo "Detected origin name ''\'''${match[2]}'" >&2 command git clone --origin "''${match[2]}" "$@" elif [[ "$1" == 'checkout' ]]; then echo 'Reminder: Use `git switch` or `git restore` instead.' >&2 command git "$@" else command git "$@" fi } rd() { diff --recursive --unified "$@" | delta } rdw() { diff --ignore-all-space --recursive --unified "$@" | delta } [[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh ''; shellAliases = { a = "git add --patch"; b = "git switch --create"; c = "git commit"; cat = "bat --plain"; code = "codium"; d = "git diff ':!*.lock'"; ds = "git diff --staged ':!*.lock'"; e = "exa --all --group-directories-first --long --header --time-style long-iso"; et = "exa --all --group-directories-first --long --header --time-style long-iso --tree"; gf = "git fetch --all --jobs 4 --prune"; gff = "git fetch --all --jobs 4 --prune && git merge --ff-only"; h = "tig --all"; mv = "mv --no-clobber --verbose"; p = "gopass"; rebase = "noglob git rebase --autostash --autosquash --interactive"; rm = "rm --one-file-system --verbose"; s = "git status"; stash = "git stash save --include-untracked"; undo = "git restore --patch"; watch = "watch --color"; }; prezto = { enable = true; pmodules = [ "environment" "terminal" "spectrum" "completion" "syntax-highlighting" "history-substring-search" "prompt" "git" ]; prompt.theme = "powerlevel10k"; syntaxHighlighting.styles = { arg0 = "fg=white,bold"; precommand = "fg=white"; # Pending https://github.com/zsh-users/zsh-syntax-highlighting/issues/432 reserved-word = "fg=blue"; }; terminal = { autoTitle = true; multiplexerTitleFormat = "%1~"; tabTitleFormat = "%1~"; windowTitleFormat = "%1~"; }; extraConfig = '' zstyle ':prezto:module:git:alias' skip 'yes' ''; }; }; }; # Environment home.sessionVariables = rec { ANSIBLE_NOCOWS = true; EDITOR = "${pkgs.vscodium}/bin/codium --wait"; EXA_COLORS = lib.concatStringsSep ":" (lib.attrsets.mapAttrsToList (k: v: "${k}=${v}") { ur = "2;37"; # the user-read permission bit uw = "2;37"; # the user-write permission bit ux = "1;32"; # the user-execute permission bit for regular files ue = "1;32"; # the user-execute for other file kinds gr = "2;37"; # the group-read permission bit gw = "2;37"; # the group-write permission bit gx = "2;37"; # the group-execute permission bit tr = "1;35"; # the others-read permission bit tw = "1;31"; # the others-write permission bit tx = "2;37"; # the others-execute permission bit su = "1;33"; # setuid, setgid, and sticky permission bits for files sf = "1;33"; # setuid, setgid, and sticky for other file kinds xa = "1;33"; # the extended attribute indicator sn = "2;37"; # the numbers of a file’s size ub = "1;37"; # the units of a file’s size if it is lower than 1 KB/Kib uk = "1;34"; # the units of a file’s size if it is between 1 KB/KiB and 1 MB/MiB um = "1;33"; # the units of a file’s size if it is between 1 MB/MiB and 1 GB/GiB ug = "1;31"; # the units of a file’s size if it is between 1 GB/GiB and 1 TB/TiB ut = "1;31"; # the units of a file’s size if it is 1 TB/TiB or higher uu = "30"; # a user that’s you un = "31"; # a user that’s someone else gu = "30"; # a group that you belong to gn = "31"; # a group you aren’t a member of da = "2;3;37"; # a file’s date lp = "2;37"; # the path of a symlink cc = "1;33"; # an escaped character in a filename }); LS_COLORS = lib.concatStringsSep ":" (lib.attrsets.mapAttrsToList (k: v: "${k}=${v}") { di = "1;36"; # directories ex = "32"; # executable files fi = "37"; # regular files pi = "3;34"; # named pipes so = "3;34"; # sockets bd = "1;34"; # block devices cd = "1;34"; # character devices ln = "35"; # symlinks or = "31"; # symlinks with no target }); VISUAL = EDITOR; VSCODE_GALLERY_CACHE_URL = "https://vscode.blob.core.windows.net/gallery/index"; VSCODE_GALLERY_CONTROL_URL = ""; VSCODE_GALLERY_ITEM_URL = "https://marketplace.visualstudio.com/items"; VSCODE_GALLERY_RECOMMENDATIONS_URL = ""; VSCODE_GALLERY_SERVICE_URL = "https://marketplace.visualstudio.com/_apis/public/gallery"; }; home.file.".npmrc".text = '' fund=false update-notifier=false ''; home.file.".p10k.zsh".source = ./p10k.zsh; # Workaround for https://github.com/NixOS/nixpkgs/issues/101616 home.file."${config.xdg.configHome}/autostart/gnome-keyring-ssh.desktop".text = '' [Desktop Entry] Type=Application Name=SSH Key Agent Hidden=true ''; home.file.".cspell.json".text = builtins.toJSON { dictionaries = [ "custom" ]; dictionaryDefinitions = [ { name = "custom"; path = ./words.txt; } ]; }; xdg.dataFile."nautilus/scripts/HEIF → Darktable" = { executable = true; text = with pkgs; '' #!${bash}/bin/bash set -Eeuxo pipefail readarray -t heifs < <( sed /^$/d <<< "$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS" ) total="''${#heifs[@]}" exec 3> >(${gnome.zenity}/bin/zenity --width 600 --progress --percentage=0 --auto-close) steps='3' links=(); for i in "''${!heifs[@]}"; do heif="''${heifs[$i]}" link="$heif.tif" tiff="/tmp/heif-darktable$heif.tif" echo "# Extracting $(basename "$heif")" >&3 echo "$(( (steps * i + 0) * 100 / (steps * total) ))" >&3 if [ ! -f "$tiff" ]; then y4m="$(mktemp --tmpdir=/dev/shm --suffix=.y4m)"; trap 'rm -f "$y4m"' EXIT exif="$(mktemp -u --tmpdir=/dev/shm --suffix=.tif)"; trap 'rm -f "$exif"' EXIT nice ${libheif}/bin/heif-convert "$heif" "$y4m" echo "$(( (steps * i + 1) * 100 / (steps * total) ))" >&3 ${ffmpeg}/bin/ffmpeg -i "$y4m" -c:v 'ppm' -f 'image2pipe' - \ | nice ${imagemagick}/bin/convert ppm:- "$exif" rm "$y4m" echo "$(( (steps * i + 2) * 100 / (steps * total) ))" >&3 ${exiftool}/bin/exiftool -overwrite_original -TagsFromFile "$heif" -Orientation= "$exif" mkdir -p "$(dirname "$tiff")" mv "$exif" "$tiff" fi if [ ! -L "$link" ]; then ln -s "$tiff" "$link" fi links+=("$link") done exec 3>&- ${darktable}/bin/darktable "''${links[@]}" & ''; }; xdg.dataFile."nautilus/scripts/HEIF,PNG,TIFF → JPEG" = { executable = true; text = with pkgs; '' #!${bash}/bin/bash set -Eeuxo pipefail paths="$(sed /^$/d <<< "$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS")" tr '\n' '\0' <<< "$paths" | xargs -0 -n 1 -P 8 nice ${mozjpeg-simple}/bin/mozjpeg ''; }; xdg.dataFile."nautilus/scripts/PNG: Optimize" = { executable = true; text = with pkgs; '' #!${bash}/bin/bash set -Eeuxo pipefail paths="$(sed /^$/d <<< "$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS")" tr '\n' '\0' <<< "$paths" \ | xargs -0 nice ${oxipng}/bin/oxipng --quiet --opt '4' --strip 'safe' --interlace '0' \ 2> >(${gnome.zenity}/bin/zenity --width 600 --progress --auto-close --auto-kill) ''; }; xdg.dataFile."nautilus/scripts/PNG: Trim" = { executable = true; text = with pkgs; '' #!${bash}/bin/bash set -Eeuxo pipefail paths="$(sed /^$/d <<< "$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS")" tr '\n' '\0' <<< "$paths" | xargs -0 -n 1 -P 8 nice ${imagemagick}/bin/mogrify -trim ''; }; }