{ pkgs, config, lib, ... }: let direnv = { # Environment variables making programs stay out of $HOME, but also needing we create a directory for them CARGOHOME = "${config.xdg.cacheHome}/cargo"; # There are config in there that we can version if one want CCACHE_DIR = "${config.xdg.cacheHome}/ccache"; # The config file alone seems to be not enough DASHT_DOCSETS_DIR = "${config.xdg.cacheHome}/dash_docsets"; GOPATH = "${config.xdg.cacheHome}/go"; GRADLE_USER_HOME = "${config.xdg.cacheHome}/gradle"; MIX_ARCHIVES = "${config.xdg.cacheHome}/mix/archives"; MONO_GAC_PREFIX = "${config.xdg.cacheHome}/mono"; npm_config_cache = "${config.xdg.cacheHome}/npm"; PARALLEL_HOME = "${config.xdg.cacheHome}/parallel"; TERMINFO = "${config.xdg.configHome}/terminfo"; WINEPREFIX = "${config.xdg.stateHome}/wineprefix/default"; YARN_CACHE_FOLDER = "${config.xdg.cacheHome}/yarn"; # TODO Some of that stuff is not really relavant any more }; in { nixpkgs.config.allowUnfree = true; programs = let commonRc = lib.strings.concatLines ([ '' # Colored ls # TODO Doesn't allow completion. Check out lsd instead _colored_ls() { ${pkgs.coreutils}/bin/ls -lh --color=always $@ | ${pkgs.gawk}/bin/awk ' BEGIN { FPAT = "([[:space:]]*[^[:space:]]+)"; OFS = ""; } { $1 = "\033[36m" $1 "\033[0m"; $2 = "\033[31m" $2 "\033[0m"; $3 = "\033[32m" $3 "\033[0m"; $4 = "\033[32m" $4 "\033[0m"; $5 = "\033[31m" $5 "\033[0m"; $6 = "\033[34m" $6 "\033[0m"; $7 = "\033[34m" $7 "\033[0m"; print } ' } alias ll="_colored_ls" alias la="_colored_ls -a" '' ] ++ map (d: "mkdir -p ${d}") (builtins.attrValues direnv)); # TODO Those directory creations should probably done on home-manager activation commonSessionVariables = { TIME_STYLE = "+%Y-%m-%d %H:%M:%S"; # Less colors LESS = "-R"; LESS_TERMCAP_mb = "$(echo $'\\E[1;31m')"; # begin blink LESS_TERMCAP_md = "$(echo $'\\E[1;36m')"; # begin bold LESS_TERMCAP_me = "$(echo $'\\E[0m')"; # reset bold/blink LESS_TERMCAP_so = "$(echo $'\\E[01;44;33m')"; # begin reverse video LESS_TERMCAP_se = "$(echo $'\\E[0m')"; # reset reverse video LESS_TERMCAP_us = "$(echo $'\\E[1;32m')"; # begin underline LESS_TERMCAP_ue = "$(echo $'\\E[0m')"; # reset underline # Fzf FZF_COMPLETION_OPTS = "${lib.strings.concatStringsSep " " config.programs.fzf.fileWidgetOptions}"; }; treatsHomeAsJunk = [ # Programs that think $HOME is a reasonable place to put their junk # and don't allow the user to change those questionable choices "adb" "audacity" "binwalk" # Should use .config according to the GitHub code though "cabal" # TODO May have options but last time I tried it it crashed "cmake" "ddd" "ghidra" "itch" "simplescreenrecorder" # Easy fix https://github.com/MaartenBaert/ssr/blob/1556ae456e833992fb6d39d40f7c7d7c337a4160/src/Main.cpp#L252 "vd" "wpa_cli" # TODO Maybe we can do something about node-gyp ]; commonShellAliases = { # Completion for existing commands ls = "ls -h --color=auto"; mkdir = "mkdir -v"; # cp = "cp -i"; # Disabled because conflicts with the ZSH/Bash one. This separation is confusing I swear. mv = "mv -iv"; free = "free -h"; df = "df -h"; ffmpeg = "ffmpeg -hide_banner"; ffprobe = "ffprobe -hide_banner"; ffplay = "ffplay -hide_banner"; # TODO Add ipython --no-confirm-exit --pdb # Frequent mistakes sl = "ls"; al = "la"; mdkir = "mkdir"; systemclt = "systemctl"; please = "sudo"; # Shortcuts for commonly used commands # ll = "ls -l"; # Disabled because would overwrite the colored one # la = "ls -la"; # Eh maybe it's not that bad, but for now let's keep compatibility s = "sudo -s -E"; # Give additional config to those programs, and not have them in my path bower = "bower --config.storage.packages=${config.xdg.cacheHome}/bower/packages --config.storage.registry=${config.xdg.cacheHome}/bower/registry --config.storage.links=${config.xdg.cacheHome}/bower/links"; gdb = "gdb -x ${config.xdg.configHome}/gdbinit"; iftop = "iftop -c ${config.xdg.configHome}/iftoprc"; lmms = "lmms --config ${config.xdg.configHome}/lmmsrc.xml"; # Preference vi = "nvim"; vim = "nvim"; wol = "wakeonlan"; # TODO Really, isn't wol better? Also wtf Arch aliases to pass because neither is installed anyways x) mutt = "neomutt"; # Bash/Zsh only cp = "cp -i --reflink=auto"; grep = "grep --color=auto"; dd = "dd status=progress"; rm = "rm -v --one-file-system"; # free = "free -m"; # Disabled because... no? Why? diff = "diff --color=auto"; dmesg = "dmesg --ctime"; wget = "wget --hsts-file ${config.xdg.cacheHome}/wget-hsts"; # Imported from scripts rms = ''${pkgs.findutils}/bin/find . -name "*.sync-conflict-*" -delete''; # Remove syncthing conflict files pw = ''${pkgs.pwgen}/bin/pwgen 32 -y''; # Generate passwords. ln((26*2+10)**32)/ln(2) ≅ 190 bits of entropy newestFile = ''${pkgs.findutils}/bin/find -type f -printf '%T+ %p\n' | sort | tail''; oldestFile = ''${pkgs.findutils}/bin/find -type f -printf '%T+ %p\n' | sort | head''; tracefiles = ''${pkgs.strace}/bin/strace -f -t -e trace=file''; } // lib.attrsets.mergeAttrsList (map (p: { "${p}" = "HOME=${config.xdg.cacheHome}/junkhome ${p}"; }) treatsHomeAsJunk); # TODO Maybe make nixpkg wrapper instead? So it also works from dmenu # Could also accept my fate... Home-manager doesn't necessarily make it easy to put things out of the home directory historySize = 100000; historyFile = "${config.xdg.stateHome}/shell_history"; in { home-manager.enable = true; bash = { enable = true; bashrcExtra = lib.strings.concatLines [ commonRc '' shopt -s expand_aliases shopt -s histappend '' ]; sessionVariables = commonSessionVariables; historySize = historySize; historyFile = historyFile; historyFileSize = historySize; historyControl = [ "erasedups" "ignoredups" "ignorespace" ]; shellAliases = commonShellAliases // config.frogeye.shellAliases; }; zsh = { enable = true; enableAutosuggestions = true; enableCompletion = true; syntaxHighlighting.enable = true; historySubstringSearch.enable = true; initExtra = lib.strings.concatLines [ commonRc (builtins.readFile ./zshrc.sh) ]; defaultKeymap = "viins"; history = { size = historySize; save = historySize; path = historyFile; expireDuplicatesFirst = true; }; sessionVariables = commonSessionVariables; shellAliases = commonShellAliases // config.frogeye.shellAliases; }; dircolors = { enable = true; enableBashIntegration = true; enableZshIntegration = true; # UPST This thing put stuff in .dircolors when it actually doesn't have to }; powerline-go = { enable = true; modules = [ "user" "host" "venv" "cwd" "perms" "git" ]; modulesRight = [ "jobs" "exit" "duration" "load" ]; settings = { colorize-hostname = true; max-width = 25; cwd-max-dir-size = 10; duration = "$( test -n \"$__TIMER\" && echo $(( $EPOCHREALTIME - $\{__TIMER:-EPOCHREALTIME})) || echo 0 )"; # UPST Implement this properly in home-manager, would allow for bash support }; extraUpdatePS1 = '' unset __TIMER echo -en "\033]0; $USER@$HOST $PWD\007" ''; }; gpg = { enable = true; homedir = "${config.xdg.stateHome}/gnupg"; settings = { # Remove fluff no-greeting = true; no-emit-version = true; no-comments = true; # Output format that I prefer keyid-format = "0xlong"; # Show fingerprints with-fingerprint = true; # Make sure to show if key is invalid # (should be default on most platform, # but just to be sure) list-options = "show-uid-validity"; verify-options = "show-uid-validity"; # Stronger algorithm (https://wiki.archlinux.org/title/GnuPG#Different_algorithm) personal-digest-preferences = "SHA512"; cert-digest-algo = "SHA512"; default-preference-list = "SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed"; personal-cipher-preferences = "TWOFISH CAMELLIA256 AES 3DES"; }; publicKeys = [{ source = builtins.fetchurl { url = "https://keys.openpgp.org/vks/v1/by-fingerprint/4FBA930D314A03215E2CDB0A8312C8CAC1BAC289"; sha256 = "sha256:10y9xqcy1vyk2p8baay14p3vwdnlwynk0fvfbika65hz2z8yw2cm"; }; trust = "ultimate"; }]; }; fzf = { enable = true; enableZshIntegration = true; defaultOptions = [ "--height 40%" "--layout=default" ]; fileWidgetOptions = [ "--preview '[[ -d {} ]] && ${pkgs.coreutils}/bin/ls -l --color=always {} || [[ \$(${pkgs.file}/bin/file --mime {}) =~ binary ]] && ${pkgs.file}/bin/file --brief {} || (${pkgs.highlight}/bin/highlight -O ansi -l {} || coderay {} || rougify {} || ${pkgs.coreutils}/bin/cat {}) 2> /dev/null | head -500'" ]; # file and friends are not in PATH by default... so here we want aboslute paths, which means those won't get reloaded. Meh. }; # TODO highlight or bat nix-index = { enable = false; # TODO Index is impossible to generate, should use https://github.com/nix-community/nix-index-database # but got no luck without flakes enableZshIntegration = true; }; less.enable = true; git = { enable = true; package = pkgs.gitFull; aliases = { "git" = "!exec git"; # In case I write one too many git }; ignores = [ "*.swp" "*.swo" "*.ycm_extra_conf.py" "tags" ".mypy_cache" ]; lfs.enable = true; userEmail = lib.mkDefault "geoffrey@frogeye.fr"; userName = lib.mkDefault "Geoffrey Frogeye"; extraConfig = { core = { editor = "nvim"; }; push = { default = "matching"; }; pull = { ff = "only"; }; } // lib.optionalAttrs config.frogeye.desktop.xorg { diff.tool = "meld"; difftool.prompt = false; "difftool \"meld\"".cmd = "${pkgs.meld}/bin/meld \"$LOCAL\" \"$REMOTE\""; # This escapes quotes, which isn't the case in the original, hoping this isn't an issue. }; # TODO Delta syntax highlighter... and other cool-looking options? }; readline = { enable = true; variables = { "bell-style" = "none"; "colored-completion-prefix" = true; "colored-stats" = true; "completion-ignore-case" = true; "completion-query-items" = 200; "editing-mode" = "vi"; "history-preserve-point" = true; "history-size" = 10000; "horizontal-scroll-mode" = false; "mark-directories" = true; "mark-modified-lines" = false; "mark-symlinked-directories" = true; "match-hidden-files" = true; "menu-complete-display-prefix" = true; "page-completions" = true; "print-completions-horizontally" = false; "revert-all-at-newline" = false; "show-all-if-ambiguous" = true; "show-all-if-unmodified" = true; "show-mode-in-prompt" = true; "skip-completed-text" = true; "visible-stats" = false; }; extraConfig = builtins.readFile ./inputrc; }; tmux = let themepack = pkgs.tmuxPlugins.mkTmuxPlugin rec { pluginName = "tmux-themepack"; version = "1.1.0"; rtpFilePath = "themepack.tmux"; src = pkgs.fetchFromGitHub { owner = "jimeh"; repo = "tmux-themepack"; rev = "${version}"; sha256 = "f6y92kYsKDFanNx5ATx4BkaB/E7UrmyIHU/5Z01otQE="; }; }; in { enable = true; mouse = false; clock24 = true; # TODO Vim mode? plugins = with pkgs.tmuxPlugins; [ sensible ]; extraConfig = builtins.readFile ./tmux.conf + "source-file ${themepack}/share/tmux-plugins/tmux-themepack/powerline/default/green.tmuxtheme\n"; }; translate-shell.enable = true; # TODO Cool config? password-store.enable = true; }; services = { gpg-agent = { enable = true; # TODO Consider not enabling it when not having any private key enableBashIntegration = true; enableZshIntegration = true; pinentryFlavor = "gtk2"; # Falls back to curses when needed }; # TODO Syncs a bit too often, also constantly asks for passphrase, which is annoying. git-sync = { enable = false; repositories = { dotfiles = { path = "${config.xdg.configHome}/dotfiles"; uri = lib.mkDefault "https://git.frogeye.fr/geoffrey/dotfiles.git"; }; }; }; }; xdg = { configFile = { "ccache.conf" = { text = "ccache_dir = ${config.xdg.cacheHome}/ccache"; }; "gdbinit" = { text = '' define hook-quit set confirm off end ''; }; "iftoprc" = { text = '' port-resolution: no promiscuous: no port-display: on link-local: yes use-bytes: yes show-totals: yes log-scale: yes ''; }; "pythonstartup.py" = { text = (builtins.readFile ./pythonstartup.py); }; "screenrc" = { text = (builtins.readFile ./screenrc); }; }; }; home = { activation = { # Prevent Virtualbox from creating a "VirtualBox VMs" folder in $HOME setVirtualboxSettings = lib.hm.dag.entryAfter [ "writeBoundary" ] '' if command -v VBoxManage > /dev/null then VBoxManage setproperty machinefolder ${config.xdg.dataHome}/virtualbox fi ''; }; stateVersion = "23.11"; language = { base = "en_US.UTF-8"; # time = "en_DK.UTF-8"; # TODO Disabled because complaints during nixos-rebuild switch }; packages = with pkgs; [ # dotfiles dependencies coreutils bash gnugrep gnused gnutar openssl wget curl python3Packages.pip rename which # shell zsh-completions nix-zsh-completions zsh-history-substring-search powerline-go # nix utils nix-diff nix-tree nix-output-monitor # terminal essentials file moreutils man unzip unrar p7zip # remote openssh rsync borgbackup # cleanup ncdu jdupes duperemove # local monitoring htop iotop iftop lsof strace pv progress speedtest-cli # multimedia toolbox sox imagemagick # password pwgen (pkgs.writeShellApplication { name = "git-sync-init"; # runtimeInputs = with pkgs; [ coreutils libnotify ]; text = (lib.strings.concatLines (map (r: ''[ -d "${r.path}" ] || ${pkgs.git}/bin/git clone "${r.uri}" "${r.path}"'') (lib.attrsets.attrValues config.services.git-sync.repositories) ) ); }) # Mail isync msmtp notmuch neomutt lynx # Organisation vdirsyncer khard khal todoman # TODO Lots of redundancy with other way things are defined here ] ++ lib.optionals pkgs.stdenv.isx86_64 [ nodePackages.insect # TODO Use whatever replaces insect, hopefully that works on aarch64 ]; sessionVariables = { # Favourite commands PAGER = "less"; EDITOR = "nvim"; # Extra config BOOT9_PATH = "${config.xdg.dataHome}/citra-emu/sysdata/boot9.bin"; CCACHE_CONFIGPATH = "${config.xdg.configHome}/ccache.conf"; # INPUTRC = "${config.xdg.configHome}/inputrc"; # UPST Will use programs.readline, but doesn't allow path setting LESSHISTFILE = "${config.xdg.stateHome}/lesshst"; NODE_REPL_HISTORY = "${config.xdg.cacheHome}/node_repl_history"; PYTHONSTARTUP = "${config.xdg.configHome}/pythonstartup.py"; # TODO I think we're not using the urxvt daemon on purpose? # TODO this should be desktop only, as a few things are too. SCREENRC = "${config.xdg.configHome}/screenrc"; SQLITE_HISTFILE = "${config.xdg.stateHome}/sqlite_history"; YARN_DISABLE_SELF_UPDATE_CHECK = "true"; # This also disable the creation of a ~/.yarnrc file } // lib.optionalAttrs config.frogeye.desktop.xorg { # Favourite commands VISUAL = "nvim"; BROWSER = "${config.programs.qutebrowser.package}/bin/qutebrowser"; # Extra config RXVT_SOCKET = "${config.xdg.stateHome}/urxvtd"; # Used to want -$HOME suffix, hopefullt this isn't needed # XAUTHORITY = "${config.xdg.configHome}/Xauthority"; # Disabled as this causes lock-ups with DMs } // direnv; # TODO Session variables only get reloaded on login I think. sessionPath = [ "${config.home.homeDirectory}/.local/bin" "${config.home.sessionVariables.GOPATH}" (builtins.toString ./scripts) ]; file = { ".face" = { # TODO Doesn't show on NixOS. See https://wiki.archlinux.org/title/LightDM#Changing_your_avatar ? source = pkgs.runCommand "face.png" { } "${pkgs.inkscape}/bin/inkscape ${./face.svg} -w 1024 -o $out"; }; }; }; }