summary refs log tree commit diff stats
path: root/user/settings
diff options
context:
space:
mode:
Diffstat (limited to 'user/settings')
-rw-r--r--user/settings/base.nix17
-rw-r--r--user/settings/darwin.nix5
-rw-r--r--user/settings/development/base.nix73
-rw-r--r--user/settings/development/golang.nix9
-rw-r--r--user/settings/development/javascript.nix71
-rw-r--r--user/settings/development/lisp.nix2
-rw-r--r--user/settings/development/rust.nix3
-rw-r--r--user/settings/development/web.nix86
-rw-r--r--user/settings/development/zig.nix3
-rw-r--r--user/settings/emacs.nix77
-rw-r--r--user/settings/fish.nix73
-rw-r--r--user/settings/fish/functions/dired.fish8
-rw-r--r--user/settings/fish/functions/magit.fish8
-rw-r--r--user/settings/fish/functions/newest.fish14
-rw-r--r--user/settings/fish/functions/oldest.fish14
-rw-r--r--user/settings/gaming.nix12
-rw-r--r--user/settings/git.nix32
-rw-r--r--user/settings/gnupg.nix16
-rw-r--r--user/settings/i3.nix3
-rw-r--r--user/settings/kitty.nix4
-rw-r--r--user/settings/music.nix1
-rw-r--r--user/settings/neovim.nix18
-rw-r--r--user/settings/nix.nix24
-rw-r--r--user/settings/nixos.nix8
-rw-r--r--user/settings/nixpkgs.nix6
-rw-r--r--user/settings/rofi.nix9
-rw-r--r--user/settings/shell.nix19
-rw-r--r--user/settings/ssh.nix4
-rw-r--r--user/settings/tabnine.nix95
-rw-r--r--user/settings/trezor.nix10
-rw-r--r--user/settings/user-interface.nix19
31 files changed, 473 insertions, 270 deletions
diff --git a/user/settings/base.nix b/user/settings/base.nix
index 7baeed1e..52cb14ac 100644
--- a/user/settings/base.nix
+++ b/user/settings/base.nix
@@ -1,4 +1,4 @@
-{ config
+args@{ config
 , lib
 , pkgs
 , ...
@@ -6,7 +6,10 @@
   imports = [
     ./neovim.nix
     ./shell.nix
+    (import <nix-index-database/home-manager-module.nix>
+      (args // { databases = import <nix-index-database/packages.nix>; }))
   ];
+
   # Let Home Manager install and manage itself.
   programs.home-manager.enable = true;
   manual = {
@@ -22,11 +25,8 @@
     in
     {
       EMAIL = "alan@alanpearce.eu";
-      MANPAGER = "bat -l man -p";
       ABDUCO_SOCKET_DIR = "${state}/abduco";
-      GNUPGHOME = "${data}/gnupg";
       SOLARGRAPH_CACHE = "${cache}/solargraph";
-      ASPELL_CONF = "per-conf ${conf}/aspell/aspell.conf; personal ${conf}/aspell/en.pws; repl ${conf}/aspell/en.prepl; dict-dir ${config.home.profileDirectory}/lib/aspell";
       ELECTRUMDIR = "${data}/electrum";
       DOCKER_CONFIG = "${conf}/docker";
       npm_config_userconfig = "${conf}/npm/config";
@@ -72,6 +72,7 @@
     ];
     config = {
       theme = "ansi";
+      style = "header-filename,header-filesize,rule";
     };
   };
   programs.nix-index-database.comma.enable = true;
@@ -98,9 +99,11 @@
       abduco
       dvtm
       walk
-      (aspellWithDicts (d: [ d.en d.en-computers d.en-science d.de ]))
-    ]
-    ++ (
+      nuspell
+    ] ++ (with pkgs.hunspellDicts; [
+      en-gb-large
+      de-de
+    ]) ++ (
       if !stdenv.isDarwin
       then [
         file
diff --git a/user/settings/darwin.nix b/user/settings/darwin.nix
index 8655b13f..acb0697b 100644
--- a/user/settings/darwin.nix
+++ b/user/settings/darwin.nix
@@ -5,6 +5,7 @@
 }: {
   home.packages = with pkgs; [
     darwin.trash
+    nh
     maid
     less
   ];
@@ -112,8 +113,8 @@
   };
 
   home.shellAliases = {
-    rb = "darwin-rebuild --flake $(ghq list -p nixfiles)";
-    rbs = "rb switch";
+    rb = "darwin-rebuild";
+    rbs = "darwin-rebuild switch";
 
     dig = "dig +noall +answer";
 
diff --git a/user/settings/development/base.nix b/user/settings/development/base.nix
index dcbf370f..5bf54172 100644
--- a/user/settings/development/base.nix
+++ b/user/settings/development/base.nix
@@ -1,5 +1,4 @@
 { config
-, lib
 , pkgs
 , ...
 }:
@@ -9,19 +8,18 @@
     [
       shellcheck
       shfmt
-      python3Packages.yamllint
       nodePackages.dockerfile-language-server-nodejs
       nodePackages.vscode-json-languageserver
       nodePackages.yaml-language-server
       lua-language-server
-      rubyPackages.solargraph
-      multimarkdown
+      taplo # toml
 
       license-cli
       just
 
       mosh
 
+      curlHTTP3
       xh
       htmlq
       jq
@@ -29,7 +27,6 @@
       miller
       watchexec
       entr
-      httping
 
       diffoscopeMinimal
 
@@ -41,34 +38,78 @@
       colima
       docker-client
     ] else [
-      zeal
+      httping
     ]);
 
   home.sessionVariables = {
     FLY_NO_UPDATE_CHECK = "1";
+    MOSH_TITLE_NOPREFIX = "1";
     LIMA_INSTANCE = "nixos";
   };
 
+  editorconfig = {
+    enable = true;
+    settings = {
+      "*" = {
+        charset = "utf-8";
+        end_of_line = "lf";
+        trim_trailing_whitespace = true;
+        insert_final_newline = true;
+        indent_style = "space";
+        indent_size = 2;
+        tab_width = 2;
+      };
+      "*.fish" = {
+        indent_size = 4;
+      };
+      justfile = {
+        indent_style = "tab";
+        tab_width = 4;
+      };
+      Makefile = {
+        indent_style = "tab";
+        tab_width = 4;
+      };
+    };
+  };
+
   home.shellAliases = {
     er = "direnv reload";
     ea = "direnv allow";
     ex = "direnv exec";
     es = "direnv status";
+    curl3 = "${pkgs.curlHTTP3}/bin/curl --http3";
   };
   programs.direnv = {
     enable = true;
     nix-direnv = {
       enable = true;
     };
+    config = {
+      global = {
+        disable_stdin = true;
+        load_dotenv = true;
+        strict_env = true;
+        hide_env_diff = true;
+      };
+      whitelist = {
+        prefix = with config.home; [
+          "${homeDirectory}/projects/alanpearce.eu"
+        ];
+      };
+    };
+    stdlib = ''
+      declare -A direnv_layout_dirs
+      direnv_layout_dir() {
+        echo "''${direnv_layout_dirs[$PWD]:=$(
+          local hash="$(${pkgs.coreutils}/bin/sha256sum - <<<"''${PWD}" | cut -c-7)"
+      		local path="''${PWD//[^a-zA-Z0-9]/-}"
+          echo "${config.xdg.cacheHome}/direnv/layouts/''${hash}''${path}"
+        )}"
+      }
+    '';
+  };
+  services.lorri = {
+    enable = pkgs.stdenv.isLinux;
   };
-  xdg.configFile."direnv/direnvrc".text = ''
-    declare -A direnv_layout_dirs
-    direnv_layout_dir() {
-      echo "''${direnv_layout_dirs[$PWD]:=$(
-        local hash="$(${pkgs.coreutils}/bin/sha256sum - <<<"''${PWD}" | cut -c-7)"
-    		local path="''${PWD//[^a-zA-Z0-9]/-}"
-        echo "${config.xdg.cacheHome}/direnv/layouts/''${hash}''${path}"
-      )}"
-    }
-  '';
 }
diff --git a/user/settings/development/golang.nix b/user/settings/development/golang.nix
index b554bd5c..a9293a31 100644
--- a/user/settings/development/golang.nix
+++ b/user/settings/development/golang.nix
@@ -2,11 +2,20 @@
   home.packages = with pkgs; [
     go
     gopls
+    godef
+    gogetdoc
     gotools
     golines
+    impl
+    gomodifytags
+    golangci-lint
+    golangci-lint-langserver
+    personal.prettier-plugin-go-template
   ];
   programs.emacs.extraPackages = epkgs: (with epkgs; [
     go-eldoc
+    go-tag
+    templ-ts-mode
   ]);
   programs.neovim.plugins = with pkgs.vimPlugins; [
     coc-go
diff --git a/user/settings/development/javascript.nix b/user/settings/development/javascript.nix
index bea1f02c..fa418cc1 100644
--- a/user/settings/development/javascript.nix
+++ b/user/settings/development/javascript.nix
@@ -3,21 +3,11 @@
 , ...
 }:
 {
-  home.packages =
-    (with pkgs; [
-      pnpm-shell-completion
-      bunyan-rs
-    ])
-    ++ (with pkgs.nodePackages; [
-      node2nix
-      nodemon
-      javascript-typescript-langserver
-      typescript-language-server
-      eslint_d
-      typescript
-      pnpm
-      npm-merge-driver
-    ]);
+  home.packages = with pkgs.nodePackages; [
+    node2nix
+    javascript-typescript-langserver
+    typescript-language-server
+  ];
 
   home.sessionVariables = {
     NO_UPDATE_NOTIFIER = "1"; # stop npm update-notifier
@@ -33,57 +23,7 @@
     };
   };
 
-  programs.emacs.extraPackages = epkgs: (with epkgs; [
-    add-node-modules-path
-    js2-mode
-    rjsx-mode
-    tide
-    typescript-mode
-  ]);
-
   home.shellAliases = {
-    ava = "bunx ava";
-    avt = "bunx ava --tap";
-    avat = "bunx ava --tap";
-    avaw = "bunx ava --watch";
-    avaf = "bunx ava --fail-fast";
-    avafw = "bunx ava --fail-fast --watch";
-    avawf = "bunx ava --fail-fast --watch";
-    pino = "bunyan";
-    mocha = "bunx mocha";
-    standard = "bunx standard";
-    tsc = "bunx tsc";
-    tslint = "bunx tslint";
-    tsnode = "bunx ts-node";
-
-    p = "pnpm";
-    pi = "pnpm install --filter=.";
-    pit = "pnpm install-test --filter=.";
-    pl = "pnpm ls";
-    pr = "pnpm run";
-    pb = "pnpm run build";
-    prb = "pnpm run build";
-    pbd = "pnpm multi run build --filter={.}...";
-    pmi = "pnpm multi install";
-    pmx = "pnpm multi exec "; # expand command aliases
-    pmr = "pnpm multi run";
-    pa = "pnpm add";
-    pad = "pnpm add --save-dev";
-    pd = "pnpm uninstall";
-    pou = "pnpm outdated";
-    pt = "pnpm test";
-    pmt = "pnpm multi test";
-    pmd = "pnpm multi uninstall";
-    pmit = "pnpm multi install-test";
-    pup = "pnpm update";
-    pupl = "pnpm update --latest";
-    ppr = "pnpm prune";
-    pprp = "pnpm prune --production";
-    pli = "pnpm link";
-    pdi = "pnpm dislink";
-    pul = "pnpm unlink";
-    px = "pnpx";
-
     bn = "bun";
     bni = "bun install";
     bna = "bun add";
@@ -130,7 +70,6 @@
   xdg.configFile."npm/config".text = ''
     prefix=''${HOME}/.local
     cache=${config.xdg.cacheHome}/npm/
-    store-dir=${config.xdg.cacheHome}/pnpm/
     always-auth=true
     sign-git-tag=true
     rebuild-bundle=false
diff --git a/user/settings/development/lisp.nix b/user/settings/development/lisp.nix
index 757a77ef..ddf0803a 100644
--- a/user/settings/development/lisp.nix
+++ b/user/settings/development/lisp.nix
@@ -3,8 +3,8 @@
 , ...
 }: {
   home.packages = with pkgs; [
+    clisp
     sbcl
-    lispPackages.quicklisp
     asdf
     cl-launch
   ] ++ lib.optionals pkgs.stdenv.hostPlatform.isLinux [
diff --git a/user/settings/development/rust.nix b/user/settings/development/rust.nix
index 46f3f4f1..c1b1a9df 100644
--- a/user/settings/development/rust.nix
+++ b/user/settings/development/rust.nix
@@ -10,7 +10,4 @@
     rust-analyzer
     clippy
   ];
-  programs.emacs.extraPackages = epkgs: (with epkgs; [
-    rustic
-  ]);
 }
diff --git a/user/settings/development/web.nix b/user/settings/development/web.nix
index 7570cadb..77b3e01d 100644
--- a/user/settings/development/web.nix
+++ b/user/settings/development/web.nix
@@ -1,5 +1,6 @@
 { config
 , pkgs
+, lib
 , ...
 }: {
   home.packages = with pkgs.nodePackages; [
@@ -7,22 +8,97 @@
     vscode-html-languageserver-bin
     csslint
     stylelint
-    prettier
   ] ++ (with pkgs; [
     flyctl
-    self.htmlformat
+    prettierd
+    personal.htmlformat
+    nodePackages.vercel
   ]);
   home.shellAliases = {
     # 0.2.25 current completion command only affects `flyctl`, although `fly` is a link to `flyctl`
     fly = "flyctl";
   };
+  programs.chromium = lib.mkIf pkgs.stdenv.isLinux {
+    enable = true;
+    package = pkgs.ungoogled-chromium;
+    extensions = [
+      # # uBlock origin
+      { id = "cjpalhdlnbpafiamejdnhcphjbkeiagm"; }
+      {
+        id = "ocaahdebbfolfmndjeplogmgcagdmblk";
+        updateUrl = "https://raw.githubusercontent.com/NeverDecaf/chromium-web-store/master/updates.xml";
+      }
+    ];
+    dictionaries = with pkgs.hunspellDictsChromium; [
+      en-gb
+      de-de
+    ];
+  };
+  programs.firefox = {
+    enable = pkgs.stdenv.isLinux;
+    package = pkgs.firefox-devedition;
+    profiles.dev-edition-default = {
+      search.default = "DuckDuckGo";
+      extensions = with pkgs.nur.repos.rycee.firefox-addons; [
+        a11ycss
+        disable-javascript
+        laboratory-by-mozilla
+        side-view
+        ublock-origin
+      ];
+      settings = {
+        "browser.aboutConfig.showWarning" = false;
+        "browser.theme.content-theme" = 1;
+        "browser.theme.toolbar-theme" = 1;
+        "browser.tabs.firefox-view" = false;
+        "extensions.activeThemeID" = "firefox-compact-light@mozilla.org";
+      };
+    };
+    policies = {
+      AutoFillCreditCardEnabled = false;
+      CaptivePortal = false;
+      Cookies = {
+        Behavior = "reject-foreign";
+      };
+      SanitizeOnShutdown = {
+        Cache = true;
+        Cookies = true;
+        FormData = true;
+      };
+      DisableFirefoxAccounts = true;
+      DisableFirefoxScreenShots = true;
+      DisableFirefoxStudies = true;
+      DisableMasterPasswordCreation = true;
+      DisablePasswordReveal = true;
+      DisablePocket = true;
+      DisableTelemetry = true;
+      DNSOverHTTPS.Enabled = false;
+      DontCheckDefaultBrowser = true;
+      EnableTrackingProtection = true;
+      GoToIntranetSiteForSingleWordEntryInAddressBar = true;
+      Homepage.URL = "http://localhost:7331";
+      NewTabPage = false;
+      NoDefaultBookmarks = true;
+      OfferToSaveLogins = false;
+      OverrideFirstRunPage = "";
+      OverridePostUpdatePage = "";
+      PasswordManagerEnabled = false;
+      PrintingEnabled = false;
+      SearchBar = "separate";
+      ShowHomeButton = true;
+      UserMessaging = {
+        ExtensionRecommendations = false;
+        FeatureRecommendations = false;
+        UrlbarInterventions = false;
+        SkipOnboarding = true;
+        MoreFromMozilla = false;
+      };
+    };
+  };
   programs.emacs.extraPackages = epkgs: (with epkgs; [
     caddyfile-mode
-    company-web
     emmet-mode
     nginx-mode
-    restclient
-    scss-mode
     web-mode
   ]);
   programs.neovim.plugins = with pkgs.vimPlugins; [
diff --git a/user/settings/development/zig.nix b/user/settings/development/zig.nix
index e5fab030..ac21267f 100644
--- a/user/settings/development/zig.nix
+++ b/user/settings/development/zig.nix
@@ -2,6 +2,9 @@
 , pkgs
 , ...
 }: {
+  home.packages = with pkgs; [
+    zls
+  ];
   programs.emacs.extraPackages = epkgs: (with epkgs; [
     zig-mode
   ]);
diff --git a/user/settings/emacs.nix b/user/settings/emacs.nix
index 8ce0c7d6..cc9deab6 100644
--- a/user/settings/emacs.nix
+++ b/user/settings/emacs.nix
@@ -6,13 +6,6 @@
 let
   inherit (pkgs) stdenv;
 
-  nativeCompileDirectory = "${config.xdg.cacheHome}/emacs/native-compile/";
-
-  darwinPath = pkgs.runCommandLocal "path_helper " { } ''
-    eval $(/usr/libexec/path_helper)
-    echo -n $PATH > $out
-  '';
-
   editorScript = pkgs.writeScriptBin "edit" ''
     #!${pkgs.runtimeShell}
     if [ -z "$1" ]; then
@@ -31,9 +24,14 @@ in
     "*.el diff=elisp"
   ];
   programs.git.extraConfig."diff.elisp" = {
-    xfuncname = "^\\((((def\\S+)|use-package)\\s+\\S+)";
+    xfuncname = "^(((;;;+ )|\\(|([ \t]+\\(((cl-|el-patch-)?def(un|var|macro|method|custom)|gb/))).*)$";
   };
 
+  services.emacs = lib.mkIf stdenv.isLinux {
+    enable = true;
+    package = config.programs.emacs.finalPackage;
+    client.enable = true;
+  };
   programs.emacs = {
     enable = true;
     package = lib.mkDefault (pkgs.emacs29.override { withGTK3 = true; });
@@ -65,6 +63,7 @@ in
         cdg = "cd (project-root)";
       };
     };
+
     extraPackages = epkgs: (with epkgs;
       [
         ace-link
@@ -80,10 +79,10 @@ in
         consult-dir
         consult-ghq
         consult-eglot
+        consult-lsp
         crux
         dired-git-info
         docker-compose-mode
-        dockerfile-mode
         dtrt-indent
         envrc
         editorconfig
@@ -101,6 +100,7 @@ in
         evil-commentary
         evil-embrace
         evil-exchange
+        evil-lion
         evil-matchit
         evil-mu4e
         evil-numbers
@@ -120,22 +120,22 @@ in
         git-gutter-fringe
         git-modes
         git-timemachine
+        gl-conf-mode # gitolite
         goto-chg
         helpful
-        ibuffer-project
         jinx
         just-mode
         justl
-        json-mode
         kind-icon
         lua-mode
-        lispy
+        lsp-mode
         lispyville
         magit
-        magit-filenotify
+        magit-todos
         markdown-mode
         marginalia
         nerd-icons
+        nix-ts-mode
         orderless
         doom-modeline
         php-mode
@@ -144,37 +144,70 @@ in
         quickrun
         rainbow-mode
         rainbow-delimiters
+        ssh-deploy
         stimmung-themes
         systemd
         tempel
         tempel-collection
         eglot-tempel
-        toml-mode
+        treemacs
+        treemacs-evil
+        treemacs-magit
+        treemacs-nerd-icons
         treesit-grammars.with-all-grammars
+        treesit-auto
         vc-msg
         vertico
         vertico-prescient
         wgrep-ag
         ws-butler
         which-key
-        yaml-mode
+        yasnippet
+        yasnippet-capf
       ]);
+    overrides = self: super: {
+      apheleia = self.melpaPackages.apheleia.overrideAttrs
+        (old: {
+          patchPhase = ''
+            substituteInPlace apheleia-formatters.el \
+              --replace-fail '"prettier"' '"prettierd"'
+          '';
+        });
+      just-mode = self.melpaPackages.just-mode.overrideAttrs (old: {
+        src = pkgs.fetchFromGitHub {
+          owner = "alanpearce";
+          repo = "just-mode.el";
+          rev = "08eb25e0641b4b6d79aa39182c70b9d40c56fc02";
+          sha256 = "13ccphbd95bn79pqbw6ycnfy1z8yd32swrhd1ljl7gwbhi7q6s0p";
+          # date = "2024-05-01T22:22:02+02:00";
+        };
+      });
+      treemacs-nerd-icons = self.melpaPackages.treemacs-nerd-icons.overrideAttrs (old: {
+        src = pkgs.fetchFromGitHub {
+          owner = "aaronmiller";
+          repo = "treemacs-nerd-icons";
+          sha256 = "171pdi5y9zym26iqi02c5p7zw9i7xxhv4csnjb7qlkkczha17jgp";
+          rev = "90b4f0868eea1ea923dee97d2c5457c21a61f37a";
+          # date = "2023-11-02T13:42:55-04:00";
+        };
+      });
+      lsp-mode = self.melpaPackages.lsp-mode.overrideAttrs {
+        LSP_USE_PLISTS = "true"; # must be set in early-init
+      };
+    };
     extraConfig = ''
       (with-eval-after-load 'editorconfig
-        (setq editorconfig-exec-path "${pkgs.editorconfig-core-c}/bin/editorconfig"))
-      (when (featurep 'native-compile)
-        (setq native-compile-target-directory "${nativeCompileDirectory}")
-        (add-to-list 'native-comp-eln-load-path "${nativeCompileDirectory}" :append))
+        (defvar editorconfig-exec-path "${pkgs.editorconfig-core-c}/bin/editorconfig"))
     '' + lib.optionalString stdenv.isDarwin ''
       (with-eval-after-load 'files
-        (setq insert-directory-program "${pkgs.coreutils-prefixed}/bin/gls"))
+        (defvar insert-directory-program "${pkgs.coreutils-prefixed}/bin/gls"))
       (with-eval-after-load 'dired
-        (setq dired-use-ls-dired t))
-      (setq exec-path (parse-colon-path (setenv "PATH" "${pkgs.lib.readFile darwinPath}")))
+        (defvar dired-use-ls-dired t))
     '';
   };
   home.packages = with pkgs; [
     editorScript
+    enchant
   ];
   xdg.configFile."raycast/scripts/Emacs" = {
     executable = true;
diff --git a/user/settings/fish.nix b/user/settings/fish.nix
index 8ed80e3e..a487418c 100644
--- a/user/settings/fish.nix
+++ b/user/settings/fish.nix
@@ -4,38 +4,32 @@
 }: {
   programs.fish = {
     enable = true;
-    plugins = [
-      {
-        name = "tide";
-        src = pkgs.fetchFromGitHub {
-          # https://github.com/IlanCosman/tide
-          owner = "IlanCosman";
-          repo = "tide";
-          rev = "a3426e157f94b8a9cb5bcf96946b1e55625a1948";
-          sha256 = "1fwqmsrd6bpf67rgj6f362abjmpk6q8yynyskc4niwg3g15diqq5";
-        };
-      }
-      {
-        name = "fzf";
-        src = pkgs.fetchFromGitHub {
-          owner = "PatrickF1";
-          repo = "fzf.fish";
-          rev = "6d00ecc6e5b2b1313cfcb25515941ecfd5342b30";
-          sha256 = "1sd5f6707hys6dibs1zb6f1imlkspqad5i24j4gf7lk9cby0zh6i";
-        };
-      }
-      {
-        name = "ghq";
-        src = pkgs.fetchFromGitHub {
-          owner = "decors";
-          repo = "fish-ghq";
-          rev = "cafaaabe63c124bf0714f89ec715cfe9ece87fa2";
-          sha256 = "0cv7jpvdfdha4hrnjr887jv1pc6vcrxv2ahy7z6x562y7fd77gg9";
-        };
-      }
-    ];
+    plugins =
+      let
+        fromNixpkgs = pkg: { name = pkg.name; src = pkg.src; };
+      in
+      with pkgs.fishPlugins; [
+        (fromNixpkgs tide)
+        (fromNixpkgs fzf-fish)
+        (fromNixpkgs autopair)
+        {
+          name = "ghq";
+          src = pkgs.fetchFromGitHub {
+            owner = "decors";
+            repo = "fish-ghq";
+            sha256 = "0cv7jpvdfdha4hrnjr887jv1pc6vcrxv2ahy7z6x562y7fd77gg9";
+            # date = "2021-07-16T13:17:09+09:00";
+            rev = "cafaaabe63c124bf0714f89ec715cfe9ece87fa2";
+          };
+        }
+      ];
+    # TODO: pre-generate nix-your-shell
     interactiveShellInit = ''
+      ${pkgs.nix-your-shell}/bin/nix-your-shell --nom fish env | source
       bind \es __ghq_repository_search
+      # don't bind ctrl-t, it does nice things on macOS/BSD
+      set FZF_CTRL_T_COMMAND
+      set --export FZF_DEFAULT_OPTS '--cycle --layout=reverse --border --height=90% --preview-window=wrap --marker="*"'
       fzf_configure_bindings --directory=\cx\cf
     '';
     shellAliases = {
@@ -51,7 +45,24 @@
     functions = {
       ds = "du -hd1 $argv[1] | sort -h";
       last_history_item = "echo $history[1]";
-    };
+    } // (lib.attrsets.optionalAttrs pkgs.stdenv.isLinux {
+      open = ''
+        argparse h/help a/application -- $argv
+        or return
+
+        if set -ql _flag_help
+           echo "open [-h|--help] [-a application] [arguments...]"
+           return 1
+        end
+
+        if set -ql _flag_application
+           # TODO: support reverse-domain- named files (e.g. org.kde.kate.desktop)
+           ${pkgs.gtk3}/bin/gtk-launch $argv[1]
+        else
+          xdg-open $argv
+        end
+      '';
+    });
   };
   xdg.configFile."fish/completions" = {
     recursive = true;
diff --git a/user/settings/fish/functions/dired.fish b/user/settings/fish/functions/dired.fish
new file mode 100644
index 00000000..a59ffac2
--- /dev/null
+++ b/user/settings/fish/functions/dired.fish
@@ -0,0 +1,8 @@
+function dired
+    if set --query argv[1]
+        set --function repo $argv[1]
+    else
+        set --function repo $pwd
+    end
+    emacsclient --suppress-output --eval "(dired \"$argv[1]\")"
+end
diff --git a/user/settings/fish/functions/magit.fish b/user/settings/fish/functions/magit.fish
new file mode 100644
index 00000000..96c90096
--- /dev/null
+++ b/user/settings/fish/functions/magit.fish
@@ -0,0 +1,8 @@
+function magit
+    if set --query argv[1]
+        set --function repo $argv[1]
+    else
+        set --function repo $pwd
+    end
+    emacsclient --suppress-output --eval "(magit-status \"$argv[1]\")"
+end
diff --git a/user/settings/fish/functions/newest.fish b/user/settings/fish/functions/newest.fish
new file mode 100644
index 00000000..3f2fa66f
--- /dev/null
+++ b/user/settings/fish/functions/newest.fish
@@ -0,0 +1,14 @@
+function newest
+    if test (count $argv) -eq 0
+        echo "Need at least one path"
+        return 1
+    end
+    for arg in $argv
+        if test -d $arg
+            fd --hidden --print0 --max-depth 1 . $arg |
+                bfs -files0-from - \( -name .git -prune \) -o \( -printf '%TY%Tm%Td%TH%TM %TF %h/%f\n' \) |
+                sort --key 1nr,1 | head --lines 1 |
+                cut -d ' ' -f 2,3
+        end
+    end
+end
diff --git a/user/settings/fish/functions/oldest.fish b/user/settings/fish/functions/oldest.fish
new file mode 100644
index 00000000..140d74cc
--- /dev/null
+++ b/user/settings/fish/functions/oldest.fish
@@ -0,0 +1,14 @@
+function oldest
+    if test (count $argv) -eq 0
+        echo "Need at least one path"
+        return 1
+    end
+    for arg in $argv
+        if test -d $arg
+            fd --hidden --print0 --max-depth 1 . $arg |
+                bfs -files0-from - \( -name .git -prune \) -o \( -printf '%TY%Tm%Td%TH%TM %TF %h/%f\n' \) |
+                sort --key 1n,1 | head --lines 1 |
+                cut -d ' ' -f 2,3
+        end
+    end
+end
diff --git a/user/settings/gaming.nix b/user/settings/gaming.nix
deleted file mode 100644
index 745c1a3e..00000000
--- a/user/settings/gaming.nix
+++ /dev/null
@@ -1,12 +0,0 @@
-{ config
-, pkgs
-, ...
-}: {
-  home.packages = with pkgs; [
-    wineWowPackages.stable
-    # winetricks
-
-    lutris
-    (discord.override { withOpenASAR = true; })
-  ];
-}
diff --git a/user/settings/git.nix b/user/settings/git.nix
index f53d33a9..769b3728 100644
--- a/user/settings/git.nix
+++ b/user/settings/git.nix
@@ -14,6 +14,14 @@
       };
     };
     extraConfig = {
+      init = {
+        defaultBranch = "main";
+      };
+      advice = {
+        addEmptyPathspec = false;
+        detachedHead = false;
+        mergeConflict = false;
+      };
       ghq = {
         root = "${config.home.homeDirectory}/projects";
         user = "alanpearce";
@@ -41,9 +49,6 @@
         algorithm = "patience";
         colorMoved = "default";
       };
-      "difftool.sopsdiffer" = {
-        textconf = "${pkgs.sops}/bin/sops -d";
-      };
       remote = {
         autoSetupMerge = true;
       };
@@ -75,8 +80,10 @@
       pending = "!sh -c 'git log --oneline --grep=\"#\" ...$(git lasttag)'";
       lg = "log --pretty=format:'%Cred%h%Creset -%Creset %s %Cgreen(%cr) %C(bold blue)<%an> %Cred%d%Creset'";
       prl = "log --pretty=format:'%Cred%h%Creset -%Creset %s %Cgreen(%cr) %C(bold blue)<%an> %Cred%d%Creset'  --grep='#'";
+      gen-ignore = "ignore-io";
       ignored = "ls-files --others -i --exclude-standard";
-      root = "rev-parse --show-toplevel";
+      clear = "clear-soft";
+      clear-hard = "!git-clear-hard";
     };
     ignores = [
       ".DS_Store"
@@ -87,4 +94,21 @@
       ".tabnine_root"
     ];
   };
+  programs.gh = {
+    enable = true;
+    settings = {
+      git_protocol = "ssh";
+      aliases = {
+        fork = "repo fork --remote --remote-name alanpearce --default-branch-only";
+      };
+    };
+  };
+  home.packages = with pkgs; [
+    git-extras # delete-merged-branches and friends
+    ghq
+    delta
+    gitui
+    gitstatus
+    hut # sourcehut tools
+  ];
 }
diff --git a/user/settings/gnupg.nix b/user/settings/gnupg.nix
index 913b5d27..d719b618 100644
--- a/user/settings/gnupg.nix
+++ b/user/settings/gnupg.nix
@@ -2,8 +2,18 @@
 , pkgs
 , ...
 }: {
-  home.file.".gnupg" = {
-    recursive = true;
-    source = ../gnupg;
+  programs.gpg = {
+    enable = true;
+    homedir = "${config.xdg.dataHome}/gnupg";
+    settings = {
+      keyserver = "hkps://keys.openpgp.org";
+    };
+  };
+  services.gpg-agent = {
+    enable = true;
+    pinentryPackage = with pkgs;
+      if stdenv.isDarwin
+      then pinentry_mac
+      else pinentry-qt;
   };
 }
diff --git a/user/settings/i3.nix b/user/settings/i3.nix
index 79a7811d..e8951062 100644
--- a/user/settings/i3.nix
+++ b/user/settings/i3.nix
@@ -7,6 +7,9 @@
     recursive = true;
     source = ../i3/i3status;
   };
+  home.sessionVariables = {
+    TERMINAL = "xterm";
+  };
   xsession.windowManager.i3 =
     let
       mod = "Mod4";
diff --git a/user/settings/kitty.nix b/user/settings/kitty.nix
index 814ce54c..c1de50d8 100644
--- a/user/settings/kitty.nix
+++ b/user/settings/kitty.nix
@@ -12,6 +12,10 @@
     shellIntegration = {
       mode = "no-cursor";
     };
+    keybindings = {
+      "ctrl+shift+t" = "new_tab_with_cwd !neighbor";
+      "cmd+t" = "new_tab_with_cwd !neighbor";
+    };
     settings = {
       macos_option_as_alt = "left";
     };
diff --git a/user/settings/music.nix b/user/settings/music.nix
index 6bd16036..3f963f35 100644
--- a/user/settings/music.nix
+++ b/user/settings/music.nix
@@ -3,7 +3,6 @@
 }: {
   home.packages = with pkgs; [
     sonixd
-    sublime-music
   ];
 
   xdg.desktopEntries.sonixd = {
diff --git a/user/settings/neovim.nix b/user/settings/neovim.nix
index 315a309b..dcee5fde 100644
--- a/user/settings/neovim.nix
+++ b/user/settings/neovim.nix
@@ -31,16 +31,22 @@
       enable = true;
       settings = {
         "json.enable" = true;
-        "suggest.enablePreview" = true;
-        "coc.preferences.formatOnSaveFiletypes" = [ "nix" ];
-        "nil.formatting.command" = "nixpkgs-fmt";
-        semantictokens = {
-          filetypes = [ "nix" ];
-        };
         languageserver = {
           nix = {
             command = "${pkgs.nil}/bin/nil";
             filetypes = [ "nix" ];
+            rootPatterns = [ "flake.nix" ];
+            settings = {
+              coc.preferences.formatOnSaveFiletypes = [ "nix" ];
+              links.tooltip = true;
+              semanticTokens = {
+                filetypes = [ "nix" ];
+              };
+              nil = {
+                formatting.command = [ "nixpkgs-fmt" ];
+                nix.flake.autoArchive = true;
+              };
+            };
           };
           lua = {
             command = "${pkgs.lua-language-server}/bin/lua-language-server";
diff --git a/user/settings/nix.nix b/user/settings/nix.nix
index ad31a47e..66c00daf 100644
--- a/user/settings/nix.nix
+++ b/user/settings/nix.nix
@@ -1,30 +1,40 @@
 { config
 , pkgs
+, lib
 , ...
 }:
 let
   toml = pkgs.formats.toml { };
 in
 {
-  imports = [
-    ../../pin.nix
-  ];
   nixpkgs.config = import ../config.nix;
+  nix = {
+    enable = true;
+    # needed for "standalone" home-manager, conflicts with module
+    package = lib.mkDefault pkgs.nix;
+    settings = {
+      use-xdg-base-directories = true;
+    };
+  };
+
   home.packages = with pkgs; [
+    cached-nix-shell
     nil
+    npins
     nix-prefetch-scripts
     nix-init
     nix-update
+    nix-tree
     common-updater-scripts
     nixpkgs-fmt
+    nixpkgs-lint
+    nixpkgs-review
+    nix-output-monitor
   ];
   xdg.configFile."nix-init/config.toml".source = toml.generate "config.toml" {
     maintainers = [ "alanpearce" ];
-    nixpkgs = "builtins.getFlake \"nixpkgs\"";
+    nixpkgs = "<nixpkgs>";
   };
-  nixpkgs.overlays = [
-    (import ../overlays/extra-packages.nix)
-  ];
   programs.emacs.extraPackages = epkgs: (with epkgs; [
     nix-mode
     nix-update
diff --git a/user/settings/nixos.nix b/user/settings/nixos.nix
index bae37c56..85ea7f72 100644
--- a/user/settings/nixos.nix
+++ b/user/settings/nixos.nix
@@ -5,9 +5,9 @@
   ];
 
   home.shellAliases = {
-    srb = "sudo nixos-rebuild";
-    rbs = "sudo nixos-rebuild switch --fast";
-    rbb = "sudo nixos-rebuild boot";
-    rbr = "sudo nixos-rebuild switch --rollback";
+    srb = "nixos-rebuild";
+    rbs = "nixos-rebuild switch --fast";
+    rbb = "nixos-rebuild boot --fast";
+    rbr = "nixos-rebuild switch --rollback";
   };
 }
diff --git a/user/settings/nixpkgs.nix b/user/settings/nixpkgs.nix
index 9f8af5c8..992f6742 100644
--- a/user/settings/nixpkgs.nix
+++ b/user/settings/nixpkgs.nix
@@ -10,10 +10,4 @@ in
   imports = [
     ./nix.nix
   ];
-  nixpkgs.overlays = [
-    (self: super: {
-      firefox-bin-unwrapped = super.firefox-bin-unwrapped.override { systemLocale = "en-GB"; };
-      firefox-devedition-bin-unwrapped = super.firefox-devedition-bin-unwrapped.override { systemLocale = "en-GB"; };
-    })
-  ];
 }
diff --git a/user/settings/rofi.nix b/user/settings/rofi.nix
index c0c6990d..35d50a91 100644
--- a/user/settings/rofi.nix
+++ b/user/settings/rofi.nix
@@ -12,15 +12,6 @@
     gui_if_available = false
   '';
 
-  nixpkgs.overlays = [
-    (self: super: {
-      rofi = super.rofi.overrideAttrs (oldAttrs: rec {
-        postInstall = ''
-          ln $out/bin/rofi $out/bin/dmenu
-        '';
-      });
-    })
-  ];
   programs.rofi = {
     enable = true;
     theme = "Arc";
diff --git a/user/settings/shell.nix b/user/settings/shell.nix
index 6542636a..fe2b4690 100644
--- a/user/settings/shell.nix
+++ b/user/settings/shell.nix
@@ -30,7 +30,7 @@ in
       llr = "ll -t";
 
       c = "lk";
-      "c," = "cd $(ghq list -p nixfiles)";
+      "c," = "cd ${config.home.homeDirectory + "/projects/alanpearce.eu/nixfiles"}";
       cg = "cd $(git root)";
       cdg = "cd $(git root)";
 
@@ -118,14 +118,18 @@ in
 
       ho = "home-manager";
       hob = "home-manager build";
-      hos = "home-manager switch";
+      hos = "home-manager switch -b hm_bak_$(date +%Y%m%d%H%M)";
       hon = "home-manager news";
       hoh = "home-manager help";
       hop = "home-manager packages";
       hol = "home-manager generations";
       hox = "home-manager expire-generations '-30 days'";
 
-      nsh = "nix shell";
+      lw = "lorri watch";
+      lw1 = "lorri watch --once";
+      lwo = "lorri watch --once";
+
+      nsh = "nix-shell";
       nb = "nix build";
       nl = "nix log"; # shadows `coreutils.nl`, but I've never used that yet
       nr = "nix run";
@@ -135,6 +139,8 @@ in
       nfp = "nix flake prefetch";
       nfu = "nix flake update";
       nfl = "nix flake lock";
+      nfsh = "nix shell";
+      ndev = "nix develop";
       nlg = "nix-env --list-generations";
       snlg = "sudo nix-env --list-generations --profile /nix/var/nix/profiles/system";
       ngc = "nix-collect-garbage --delete-older-than 30d";
@@ -142,13 +148,8 @@ in
     };
   };
   home.packages = with pkgs; [
+    babashka
     fzf
-    gh
-    ghq
-    delta
-    git
-    gitui
-    gitstatus
     up
   ];
 }
diff --git a/user/settings/ssh.nix b/user/settings/ssh.nix
index f5073c8d..b7c46bba 100644
--- a/user/settings/ssh.nix
+++ b/user/settings/ssh.nix
@@ -12,6 +12,10 @@
     serverAliveInterval = 15;
     extraConfig = ''
       VerifyHostKeyDNS ask
+      CanonicalizeHostname yes
+      CanonicalizeFallbackLocal no
+      CanonicalizeMaxDots 0
+      CanonicalDomains home.arpa hydra-pinecone.ts.net
     '';
     includes = [
       "local.ssh_config"
diff --git a/user/settings/tabnine.nix b/user/settings/tabnine.nix
index 4cb1be3b..9502c68d 100644
--- a/user/settings/tabnine.nix
+++ b/user/settings/tabnine.nix
@@ -10,10 +10,47 @@
     config = {
       version = pkgs.tabnine.version;
 
-      hide_promotional_message = true;
+      api_base_url = null;
+      api_key = config.programs.tabnine.registrationKey;
       beta_enabled = "No";
-      ignore_all_lsp = false;
+      binary_update_interval_seconds = 365 * 24 * 3600;
+      cloud_whitelist = [ ];
       creation_time = "2020-12-28T21:42:35.732522096Z";
+      deep_completions_work_mode = "LocalOnly";
+      disable_auto_update = true;
+      disable_local_when_using_battery = false;
+      enable_power_saving_mode = false;
+      enable_telemetry = false;
+      exclude_file_masks = true;
+      force_local_hub = true;
+      generation = 0;
+      guuid = null;
+      gusr.gcgdc = "0000000000000000000000000000000000000000000000000000000000000000";
+      has_git_repos = null;
+      heartbeat_interval_seconds = null;
+      hide_deep_information_message = false;
+      hide_promotional_message = true;
+      hosted_deep_completions_enabled = "Disabled";
+      ignore_all_lsp = false;
+      inline_suggestions_mode = true;
+      inline_suggestions_mode_clients = null;
+      last_service_level = null;
+      line_suggestions = true;
+      local_enabled = "Yes";
+      local_indexing = null;
+      local_model_size = null;
+      manually_selected_model = null;
+      model_hash_override = null;
+      num_of_suggestions = 5;
+      omit_prefix_suggestions = null;
+      onboarding = {
+        model_type = null;
+        skipped_login = true;
+        completed = true;
+      };
+      rate_limit_amount = null;
+      rate_limit_interval_seconds = null;
+      rlhf = null;
       semantic_status = {
         css = "Enabled";
         dockerfile = "Enabled";
@@ -21,81 +58,65 @@
         haskell = "Enabled";
         html = "Enabled";
         javascript = "Enabled";
-        ruby = "Enabled";
         nix = "Enabled";
+        ruby = "Enabled";
         scss = "Enabled";
         typescript = "Enabled";
         yaml = "Enabled";
       };
-      disable_auto_update = true;
-      binary_update_interval_seconds = 365 * 24 * 3600;
-      deep_completions_work_mode = "LocalOnly";
-      hosted_deep_completions_enabled = "Disabled";
+      snippets_enabled_v2 = true;
       tabnine_cloud_certificate_domain = null;
       tabnine_cloud_host = null;
       tabnine_cloud_port = null;
-      cloud_whitelist = [ ];
-      api_key = null;
-      api_key_service_level = null;
-      api_base_url = null;
-      local_enabled = "Yes";
-      local_indexing = null;
-      local_model_size = null;
-      disable_local_when_using_battery = false;
-      hide_deep_information_message = false;
-      enable_power_saving_mode = false;
-      enable_telemetry = false;
-      generation = "0";
-      rate_limit_interval_seconds = null;
-      rate_limit_amount = null;
+      tabnine_hub_port = null;
+      use_specialized_model_if_available = true;
+      user_understands_that_enabling_tabnine_cloud_sends_code_to_tabnine_servers = false;
     };
-    lspConfig = {
-      "language.typescript" = {
+    lspConfig.language = {
+      typescript = {
         command = "typescript-language-server";
         args = [ "--stdio" ];
       };
-      "language.javascript" = {
+      javascript = {
         command = "javascript-typescript-stdio";
         args = [ "--stdio" ];
       };
-      "language.css" = {
+      css = {
         command = "css-languageserver";
         args = [ "--stdio" ];
       };
-      "language.scss" = {
+      scss = {
         command = "css-languageserver";
         args = [ "--stdio" ];
       };
-      "language.html" = {
+      html = {
         command = "html-languageserver";
         args = [ "--stdio" ];
       };
-      "language.nix" = {
+      nix = {
         command = "nil";
         args = [ "--stdio" ];
       };
-      "language.dockerfile" = {
+      dockerfile = {
         command = "docker-langserver";
         args = [ "--stdio" ];
       };
-      "language.ruby" = {
+      ruby = {
         command = "solargraph";
         args = [ "stdio" ];
       };
-      "language.yaml" = {
+      yaml = {
         command = "yaml-language-server";
         args = [ "--stdio" ];
       };
-      "language.haskell" = {
+      haskell = {
         command = "hie";
         args = [ "--stdio" ];
       };
-      "language.go" = {
-        command = "go-langserver";
+      go = {
+        command = "gopls";
         args = [
-          "-mode"
-          "stdio"
-          "-gocodecompletion"
+          "serve"
         ];
       };
     };
diff --git a/user/settings/trezor.nix b/user/settings/trezor.nix
deleted file mode 100644
index 6996d9b0..00000000
--- a/user/settings/trezor.nix
+++ /dev/null
@@ -1,10 +0,0 @@
-{ config
-, pkgs
-, ...
-}: {
-  home.file.".ssh/agent.config" = {
-    text = ''
-      ecdsa-curve-name = ed25519
-    '';
-  };
-}
diff --git a/user/settings/user-interface.nix b/user/settings/user-interface.nix
index 469bdde4..29de4439 100644
--- a/user/settings/user-interface.nix
+++ b/user/settings/user-interface.nix
@@ -6,9 +6,9 @@ let
   inherit (pkgs) stdenv;
 in
 {
-  home.sessionVariables = {
-    TERMINAL = "xterm";
-  };
+  imports = [
+    ./kitty.nix
+  ];
 
   services.ssh-agent = {
     enable = stdenv.hostPlatform.isLinux;
@@ -26,8 +26,6 @@ in
   };
   home.packages = with pkgs;
     [
-      kitty
-
       hack-font
       ibm-plex
       inter
@@ -38,20 +36,23 @@ in
       # see https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/data/fonts/nerdfonts/shas.nix
       (nerdfonts.override {
         fonts = [
-          "Hack"
           "JetBrainsMono"
           "IBMPlexMono"
           "iA-Writer"
-          "Meslo"
           "NerdFontsSymbolsOnly"
         ];
       })
     ]
     ++ lib.optionals (!stdenv.isDarwin) (with pkgs; [
-      logseq
+      logseq # 0.10.9 is insecure, see ../config.nix
+      (discord.override { withOpenASAR = true; })
 
+      zeal
       falkon
-      mu
       beeper
+      kdePackages.neochat
+      kdePackages.kleopatra
     ]);
+  services.lorri.enableNotifications = true;
+  services.emacs.startWithUserSession = "graphical";
 }