From 4630d10b3151f689247c0e8e7488917ee6313c7f Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 17 May 2019 12:50:48 +0200
Subject: [PATCH 01/19] github-hosts-sync: import 1.0.0 from painload

---
 .../simple/github-hosts-sync/default.nix      |  4 +-
 .../simple/github-hosts-sync/src/hosts-sync   | 66 +++++++++++++++++++
 2 files changed, 68 insertions(+), 2 deletions(-)
 create mode 100755 krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync

diff --git a/krebs/5pkgs/simple/github-hosts-sync/default.nix b/krebs/5pkgs/simple/github-hosts-sync/default.nix
index cdfed468c..8caa5e1ef 100644
--- a/krebs/5pkgs/simple/github-hosts-sync/default.nix
+++ b/krebs/5pkgs/simple/github-hosts-sync/default.nix
@@ -3,7 +3,7 @@
 stdenv.mkDerivation {
   name = "github-hosts-sync";
 
-  src = pkgs.painload;
+  src = ./src;
 
   phases = [
     "unpackPhase"
@@ -29,7 +29,7 @@ stdenv.mkDerivation {
 
       sed \
         's,^main() {$,&\n  export PATH=${path} GIT_SSL_CAINFO=${ca-bundle},' \
-        < ./retiolum/scripts/github_hosts_sync/hosts-sync \
+        < hosts-sync \
         > $out/bin/github-hosts-sync
 
       chmod +x $out/bin/github-hosts-sync
diff --git a/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync b/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync
new file mode 100755
index 000000000..f36c700d8
--- /dev/null
+++ b/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync
@@ -0,0 +1,66 @@
+#! /bin/sh
+# TODO do_work should retry until success
+set -euf
+
+port=${port-1028}
+local_painload=$HOME/painload
+remote_painload="https://github.com/krebscode/painload"
+local_hosts=$HOME/hosts
+remote_hosts="git@github.com:krebscode/hosts.git"
+
+main() {
+  ensure_local_painload
+  ensure_local_hosts
+  is_worker && do_work || become_server
+}
+
+ensure_local_painload() {
+  test -d "$local_painload" || git clone "$remote_painload" "$local_painload"
+}
+
+ensure_local_hosts() {
+  test -d "$local_hosts" || git clone "$remote_hosts" "$local_hosts"
+}
+
+become_server() {
+  exec socat "TCP-LISTEN:$port,reuseaddr,fork" "EXEC:$0"
+}
+
+is_worker() {
+  test "${SOCAT_SOCKPORT-}" = "$port"
+}
+
+do_work() {
+  # read request
+  req_line="$(read line && echo "$line")"
+  req_hdrs="$(sed -n '/^\r$/q;p')"
+
+  set -x
+
+  cd "$local_hosts"
+  git pull >&2
+
+  cd "$local_hosts"
+  find . -name .git -prune -o -type f -exec git rm \{\} \; >/dev/null
+
+  cd "$local_painload"
+  git pull >&2
+
+  find "$local_painload/retiolum/hosts" -type f -exec cp \{\} "$local_hosts" \;
+
+  cd "$local_hosts"
+  find . -name .git -prune -o -type f -exec git add \{\} \; >&2
+  if git status --porcelain | grep -q .; then
+    git config user.email "$LOGNAME@$(hostname)"
+    git config user.name "$LOGNAME"
+    git commit -m bump >&2
+    git push >&2
+  fi
+
+  echo "HTTP/1.1 200 OK"
+  echo
+  echo "https://github.com/krebscode/hosts/archive/master.tar.gz"
+  echo "https://github.com/krebscode/hosts/archive/master.zip"
+}
+
+main "$@"

From acb3f95fa6586a9c9b1b1ffa76368c1b39edb8aa Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 17 May 2019 13:06:36 +0200
Subject: [PATCH 02/19] github-hosts-sync: 1.0.0 -> 2.0.0

---
 krebs/3modules/github-hosts-sync.nix          | 25 ++++--
 .../simple/github-hosts-sync/default.nix      | 36 ++++-----
 .../simple/github-hosts-sync/src/hosts-sync   | 81 ++++++-------------
 3 files changed, 56 insertions(+), 86 deletions(-)

diff --git a/krebs/3modules/github-hosts-sync.nix b/krebs/3modules/github-hosts-sync.nix
index 3b626dc46..233cea68d 100644
--- a/krebs/3modules/github-hosts-sync.nix
+++ b/krebs/3modules/github-hosts-sync.nix
@@ -11,17 +11,25 @@ let
 
   api = {
     enable = mkEnableOption "krebs.github-hosts-sync";
-    port = mkOption {
-      type = types.int; # TODO port type
-      default = 1028;
-    };
     dataDir = mkOption {
       type = types.str; # TODO path (but not just into store)
       default = "/var/lib/github-hosts-sync";
     };
+    srcDir = mkOption {
+      type = types.str;
+      default = "${config.krebs.tinc.retiolum.confDir}/hosts";
+    };
     ssh-identity-file = mkOption {
       type = types.suffixed-str [".ssh.id_ed25519" ".ssh.id_rsa"];
-      default = toString <secrets/github-hosts-sync.ssh.id_rsa>;
+      default = toString <secrets/github-hosts-sync.ssh.id_ed25519>;
+    };
+    url = mkOption {
+      type = types.str;
+      default = "git@github.com:krebscode/hosts.git";
+    };
+    workTree = mkOption {
+      type = types.absolute-pathname;
+      default = "${cfg.dataDir}/cache";
     };
   };
 
@@ -30,13 +38,16 @@ let
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       environment = {
-        port = toString cfg.port;
+        GITHUB_HOST_SYNC_SRCDIR = cfg.srcDir;
+        GITHUB_HOST_SYNC_WORKTREE = cfg.workTree;
+        GITHUB_HOST_SYNC_URL = cfg.url;
       };
       serviceConfig = {
         PermissionsStartOnly = "true";
         SyslogIdentifier = "github-hosts-sync";
         User = user.name;
-        Restart = "always";
+        Type = "oneshot";
+        RemainAfterExit = true;
         ExecStartPre = pkgs.writeDash "github-hosts-sync-init" ''
           set -euf
           install -m 0711 -o ${user.name} -d ${cfg.dataDir}
diff --git a/krebs/5pkgs/simple/github-hosts-sync/default.nix b/krebs/5pkgs/simple/github-hosts-sync/default.nix
index 8caa5e1ef..5caf225cb 100644
--- a/krebs/5pkgs/simple/github-hosts-sync/default.nix
+++ b/krebs/5pkgs/simple/github-hosts-sync/default.nix
@@ -1,7 +1,8 @@
 { pkgs, stdenv, ... }:
 
-stdenv.mkDerivation {
-  name = "github-hosts-sync";
+stdenv.mkDerivation rec {
+  name = "github-hosts-sync-${version}";
+  version = "2.0.0";
 
   src = ./src;
 
@@ -10,28 +11,21 @@ stdenv.mkDerivation {
     "installPhase"
   ];
 
-  installPhase =
-    let
-      ca-bundle = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
-      path = stdenv.lib.makeBinPath (with pkgs; [
-        coreutils
-        findutils
-        git
-        gnugrep
-        gnused
-        nettools
-        openssh
-        socat
-      ]);
-    in
+  installPhase = let
+    ca-bundle = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
+    path = stdenv.lib.makeBinPath [
+      pkgs.git
+      pkgs.openssh
+      pkgs.rsync
+    ];
+  in
     ''
       mkdir -p $out/bin
 
-      sed \
-        's,^main() {$,&\n  export PATH=${path} GIT_SSL_CAINFO=${ca-bundle},' \
-        < hosts-sync \
-        > $out/bin/github-hosts-sync
+      cp hosts-sync $out/bin/github-hosts-sync
 
-      chmod +x $out/bin/github-hosts-sync
+      sed -i \
+        '1s,$,\nPATH=${path}''${PATH+:$PATH} GIT_SSL_CAINFO=${ca-bundle},' \
+        $out/bin/github-hosts-sync
     '';
 }
diff --git a/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync b/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync
index f36c700d8..4bae44bef 100755
--- a/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync
+++ b/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync
@@ -1,66 +1,31 @@
 #! /bin/sh
-# TODO do_work should retry until success
-set -euf
+set -efu
+exec >&2
 
-port=${port-1028}
-local_painload=$HOME/painload
-remote_painload="https://github.com/krebscode/painload"
-local_hosts=$HOME/hosts
-remote_hosts="git@github.com:krebscode/hosts.git"
+hosts_srcdir=$GITHUB_HOST_SYNC_SRCDIR
+hosts_worktree=${GITHUB_HOST_SYNC_WORKTREE-/tmp/hosts}
+hosts_url=${GITHUB_HOST_SYNC_URL-git@github.com:krebscode/hosts.git}
 
-main() {
-  ensure_local_painload
-  ensure_local_hosts
-  is_worker && do_work || become_server
-}
+test -d "$hosts_worktree" || git clone "$hosts_url" "$hosts_worktree"
 
-ensure_local_painload() {
-  test -d "$local_painload" || git clone "$remote_painload" "$local_painload"
-}
+cd "$hosts_worktree"
 
-ensure_local_hosts() {
-  test -d "$local_hosts" || git clone "$remote_hosts" "$local_hosts"
-}
+git pull
 
-become_server() {
-  exec socat "TCP-LISTEN:$port,reuseaddr,fork" "EXEC:$0"
-}
+rsync \
+    --chmod D755,F644 \
+    --delete-excluded \
+    --filter 'protect .git' \
+    --recursive \
+    --verbose \
+    "$hosts_srcdir/" \
+    .
 
-is_worker() {
-  test "${SOCAT_SOCKPORT-}" = "$port"
-}
+git add .
 
-do_work() {
-  # read request
-  req_line="$(read line && echo "$line")"
-  req_hdrs="$(sed -n '/^\r$/q;p')"
-
-  set -x
-
-  cd "$local_hosts"
-  git pull >&2
-
-  cd "$local_hosts"
-  find . -name .git -prune -o -type f -exec git rm \{\} \; >/dev/null
-
-  cd "$local_painload"
-  git pull >&2
-
-  find "$local_painload/retiolum/hosts" -type f -exec cp \{\} "$local_hosts" \;
-
-  cd "$local_hosts"
-  find . -name .git -prune -o -type f -exec git add \{\} \; >&2
-  if git status --porcelain | grep -q .; then
-    git config user.email "$LOGNAME@$(hostname)"
-    git config user.name "$LOGNAME"
-    git commit -m bump >&2
-    git push >&2
-  fi
-
-  echo "HTTP/1.1 200 OK"
-  echo
-  echo "https://github.com/krebscode/hosts/archive/master.tar.gz"
-  echo "https://github.com/krebscode/hosts/archive/master.zip"
-}
-
-main "$@"
+if test -n "$(git status --porcelain)"; then
+  git config user.email "$LOGNAME@$(hostname)"
+  git config user.name "$LOGNAME"
+  git commit -m bump
+  git push
+fi

From 866e94b4fa70181b9ae753b51d59c27ce42c9497 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 17 May 2019 13:36:13 +0200
Subject: [PATCH 03/19] hotdog.r: enable github-hosts-sync

---
 krebs/1systems/hotdog/config.nix | 1 +
 1 file changed, 1 insertion(+)

diff --git a/krebs/1systems/hotdog/config.nix b/krebs/1systems/hotdog/config.nix
index f68c8ce50..32e416831 100644
--- a/krebs/1systems/hotdog/config.nix
+++ b/krebs/1systems/hotdog/config.nix
@@ -18,6 +18,7 @@
   ];
 
   krebs.build.host = config.krebs.hosts.hotdog;
+  krebs.github-hosts-sync.enable = true;
 
   boot.isContainer = true;
   networking.useDHCP = false;

From c7cfc7d6a3988615fd40369d0e02bd570a52bc7f Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 17 May 2019 13:43:13 +0200
Subject: [PATCH 04/19] github-hosts-sync: update default URL

---
 krebs/3modules/github-hosts-sync.nix                | 2 +-
 krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/krebs/3modules/github-hosts-sync.nix b/krebs/3modules/github-hosts-sync.nix
index 233cea68d..6ffaf5503 100644
--- a/krebs/3modules/github-hosts-sync.nix
+++ b/krebs/3modules/github-hosts-sync.nix
@@ -25,7 +25,7 @@ let
     };
     url = mkOption {
       type = types.str;
-      default = "git@github.com:krebscode/hosts.git";
+      default = "git@github.com:krebs/hosts.git";
     };
     workTree = mkOption {
       type = types.absolute-pathname;
diff --git a/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync b/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync
index 4bae44bef..d2017ef63 100755
--- a/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync
+++ b/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync
@@ -4,7 +4,7 @@ exec >&2
 
 hosts_srcdir=$GITHUB_HOST_SYNC_SRCDIR
 hosts_worktree=${GITHUB_HOST_SYNC_WORKTREE-/tmp/hosts}
-hosts_url=${GITHUB_HOST_SYNC_URL-git@github.com:krebscode/hosts.git}
+hosts_url=${GITHUB_HOST_SYNC_URL-git@github.com:krebs/hosts.git}
 
 test -d "$hosts_worktree" || git clone "$hosts_url" "$hosts_worktree"
 

From e91f56a4092b47aea6dd62e015176c0a45b6e0e6 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 17 May 2019 13:48:48 +0200
Subject: [PATCH 05/19] krebs: add dummy github-hosts-sync.ssh.id_ed25519

---
 krebs/0tests/data/secrets/github-hosts-sync.ssh.id_ed25519 | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 krebs/0tests/data/secrets/github-hosts-sync.ssh.id_ed25519

diff --git a/krebs/0tests/data/secrets/github-hosts-sync.ssh.id_ed25519 b/krebs/0tests/data/secrets/github-hosts-sync.ssh.id_ed25519
new file mode 100644
index 000000000..e69de29bb

From 2950b893b03253ef8000e939915bb9c8c1f1f524 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 17 May 2019 13:53:55 +0200
Subject: [PATCH 06/19] github-hosts-sync: add nettools

---
 krebs/5pkgs/simple/github-hosts-sync/default.nix | 1 +
 1 file changed, 1 insertion(+)

diff --git a/krebs/5pkgs/simple/github-hosts-sync/default.nix b/krebs/5pkgs/simple/github-hosts-sync/default.nix
index 5caf225cb..fbc48fa3f 100644
--- a/krebs/5pkgs/simple/github-hosts-sync/default.nix
+++ b/krebs/5pkgs/simple/github-hosts-sync/default.nix
@@ -15,6 +15,7 @@ stdenv.mkDerivation rec {
     ca-bundle = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
     path = stdenv.lib.makeBinPath [
       pkgs.git
+      pkgs.nettools
       pkgs.openssh
       pkgs.rsync
     ];

From a666abeaabbed73749cd5e2f1745b4a4527c4bc6 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 17 May 2019 14:02:22 +0200
Subject: [PATCH 07/19] github-hosts-sync: make user name/mail overridable

---
 krebs/3modules/github-hosts-sync.nix                | 3 +++
 krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync | 6 ++++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/krebs/3modules/github-hosts-sync.nix b/krebs/3modules/github-hosts-sync.nix
index 6ffaf5503..0b7d56098 100644
--- a/krebs/3modules/github-hosts-sync.nix
+++ b/krebs/3modules/github-hosts-sync.nix
@@ -38,6 +38,8 @@ let
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       environment = {
+        GITHUB_HOST_SYNC_USER_MAIL = user.mail;
+        GITHUB_HOST_SYNC_USER_NAME = user.name;
         GITHUB_HOST_SYNC_SRCDIR = cfg.srcDir;
         GITHUB_HOST_SYNC_WORKTREE = cfg.workTree;
         GITHUB_HOST_SYNC_URL = cfg.url;
@@ -67,6 +69,7 @@ let
   };
 
   user = rec {
+    mail = "${name}@${config.krebs.build.host.name}";
     name = "github-hosts-sync";
     uid = genid_uint31 name;
   };
diff --git a/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync b/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync
index d2017ef63..a8973e72b 100755
--- a/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync
+++ b/krebs/5pkgs/simple/github-hosts-sync/src/hosts-sync
@@ -5,6 +5,8 @@ exec >&2
 hosts_srcdir=$GITHUB_HOST_SYNC_SRCDIR
 hosts_worktree=${GITHUB_HOST_SYNC_WORKTREE-/tmp/hosts}
 hosts_url=${GITHUB_HOST_SYNC_URL-git@github.com:krebs/hosts.git}
+user_mail=${GITHUB_HOST_SYNC_USER_MAIL-$LOGNAME@$(hostname)}
+user_name=${GITHUB_HOST_SYNC_USER_NAME-$LOGNAME}
 
 test -d "$hosts_worktree" || git clone "$hosts_url" "$hosts_worktree"
 
@@ -24,8 +26,8 @@ rsync \
 git add .
 
 if test -n "$(git status --porcelain)"; then
-  git config user.email "$LOGNAME@$(hostname)"
-  git config user.name "$LOGNAME"
+  git config user.email "$user_mail"
+  git config user.name "$user_name"
   git commit -m bump
   git push
 fi

From 87e1da05aa253a629e5e188fac4c1a572e9e61de Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Mon, 20 May 2019 14:18:40 +0200
Subject: [PATCH 08/19] tv x220: define all the lidSwitch* T_T

---
 tv/2configs/hw/x220.nix | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/tv/2configs/hw/x220.nix b/tv/2configs/hw/x220.nix
index 35e7d8941..699b4a87e 100644
--- a/tv/2configs/hw/x220.nix
+++ b/tv/2configs/hw/x220.nix
@@ -57,6 +57,11 @@
     HandleSuspendKey=ignore
   '';
 
+  # because extraConfig is not extra enough:
+  services.logind.lidSwitch = "ignore";
+  services.logind.lidSwitchDocked = "ignore";
+  services.logind.lidSwitchExternalPower = "ignore";
+
   services.xserver = {
     videoDriver = "intel";
   };

From eb9c9b80cafbb69d858a9914eda1d5aa65745ae5 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 21 May 2019 10:39:18 +0200
Subject: [PATCH 09/19] github-known-hosts: add new hosts

---
 krebs/3modules/github-known-hosts.nix | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/krebs/3modules/github-known-hosts.nix b/krebs/3modules/github-known-hosts.nix
index def06f17a..bae8b96bf 100644
--- a/krebs/3modules/github-known-hosts.nix
+++ b/krebs/3modules/github-known-hosts.nix
@@ -28,12 +28,22 @@
       "140.82.125.*"
       "140.82.126.*"
       "140.82.127.*"
+      "13.114.40.48"
       "13.229.188.59"
+      "13.234.176.102"
+      "13.234.210.38"
+      "13.236.229.21"
+      "13.237.44.5"
       "13.250.177.223"
+      "15.164.81.167"
       "18.194.104.89"
       "18.195.85.27"
       "35.159.8.160"
+      "52.192.72.89"
+      "52.64.108.95"
+      "52.69.186.44"
       "52.74.223.119"
+      "52.78.231.108"
     ];
     publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==";
   };

From 8837981c5972d745af6ce0a6a5a7d956b579575e Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 21 May 2019 21:47:43 +0200
Subject: [PATCH 10/19] tv pkgs: add vim overlay

---
 tv/5pkgs/vim/default.nix | 7 +++++++
 1 file changed, 7 insertions(+)
 create mode 100644 tv/5pkgs/vim/default.nix

diff --git a/tv/5pkgs/vim/default.nix b/tv/5pkgs/vim/default.nix
new file mode 100644
index 000000000..5582be3fd
--- /dev/null
+++ b/tv/5pkgs/vim/default.nix
@@ -0,0 +1,7 @@
+with import <stockholm/lib>;
+
+self: super: {
+  tv = super.tv // {
+    vimPlugins = mapNixDir (path: self.callPackage path {}) ./.;
+  };
+}

From 36ecf283d253a24f2ff3c434a5cda4f69119beff Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 21 May 2019 21:48:36 +0200
Subject: [PATCH 11/19] tv vim: move fzf to overlay

---
 tv/2configs/vim.nix  | 10 +---------
 tv/5pkgs/vim/fzf.nix | 11 +++++++++++
 2 files changed, 12 insertions(+), 9 deletions(-)
 create mode 100644 tv/5pkgs/vim/fzf.nix

diff --git a/tv/2configs/vim.nix b/tv/2configs/vim.nix
index a45e040e6..948058216 100644
--- a/tv/2configs/vim.nix
+++ b/tv/2configs/vim.nix
@@ -14,15 +14,7 @@ let {
   };
 
   extra-runtimepath = concatMapStringsSep "," (pkg: "${pkg.rtp}") [
-    # cannot use pkgs.vimPlugins.fzf-vim as it's missing :Rg
-    (pkgs.vimUtils.buildVimPlugin {
-      name = "fzf-2018-11-14";
-      src = pkgs.fetchgit {
-        url = https://github.com/junegunn/fzf.vim;
-        rev = "ad1833ecbc9153b6e34a4292dc089a58c4bcb8dc";
-        sha256 = "1z2q71q6l9hq9fqfqpj1svhyk4yk1bzw1ljhksx4bnpz8gkfbx2m";
-      };
-    })
+    pkgs.tv.vimPlugins.fzf
     pkgs.vimPlugins.fzfWrapper
     pkgs.vimPlugins.undotree
     (pkgs.vimUtils.buildVimPlugin {
diff --git a/tv/5pkgs/vim/fzf.nix b/tv/5pkgs/vim/fzf.nix
new file mode 100644
index 000000000..14b6900b5
--- /dev/null
+++ b/tv/5pkgs/vim/fzf.nix
@@ -0,0 +1,11 @@
+{ pkgs }:
+
+# cannot use pkgs.vimPlugins.fzf-vim as it's missing :Rg
+pkgs.vimUtils.buildVimPlugin {
+  name = "fzf-2018-11-14";
+  src = pkgs.fetchgit {
+    url = https://github.com/junegunn/fzf.vim;
+    rev = "ad1833ecbc9153b6e34a4292dc089a58c4bcb8dc";
+    sha256 = "1z2q71q6l9hq9fqfqpj1svhyk4yk1bzw1ljhksx4bnpz8gkfbx2m";
+  };
+}

From d808a760e15a2ede3699c05f160eddaf81f1efbf Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 21 May 2019 21:51:13 +0200
Subject: [PATCH 12/19] tv vim: move elixir to overlay

---
 tv/2configs/vim.nix     | 9 +--------
 tv/5pkgs/vim/elixir.nix | 9 +++++++++
 2 files changed, 10 insertions(+), 8 deletions(-)
 create mode 100644 tv/5pkgs/vim/elixir.nix

diff --git a/tv/2configs/vim.nix b/tv/2configs/vim.nix
index 948058216..934704295 100644
--- a/tv/2configs/vim.nix
+++ b/tv/2configs/vim.nix
@@ -14,17 +14,10 @@ let {
   };
 
   extra-runtimepath = concatMapStringsSep "," (pkg: "${pkg.rtp}") [
+    pkgs.tv.vimPlugins.elixir
     pkgs.tv.vimPlugins.fzf
     pkgs.vimPlugins.fzfWrapper
     pkgs.vimPlugins.undotree
-    (pkgs.vimUtils.buildVimPlugin {
-      name = "vim-elixir-2018-08-17";
-      src = pkgs.fetchgit {
-        url = https://github.com/elixir-editors/vim-elixir;
-        rev = "0a847f0faed5ba2d94bb3d51f355c50f37ba025b";
-        sha256 = "1jl85wpgywhcvhgw02y8zpvqf0glr4i8522kxpvhsiacb1v1xh04";
-      };
-    })
     (pkgs.vimUtils.buildVimPlugin {
       name = "vim-syntax-jq";
       src = pkgs.fetchgit {
diff --git a/tv/5pkgs/vim/elixir.nix b/tv/5pkgs/vim/elixir.nix
new file mode 100644
index 000000000..2ffbbc82f
--- /dev/null
+++ b/tv/5pkgs/vim/elixir.nix
@@ -0,0 +1,9 @@
+{ pkgs }:
+pkgs.vimUtils.buildVimPlugin {
+  name = "vim-elixir-2018-08-17";
+  src = pkgs.fetchgit {
+    url = https://github.com/elixir-editors/vim-elixir;
+    rev = "0a847f0faed5ba2d94bb3d51f355c50f37ba025b";
+    sha256 = "1jl85wpgywhcvhgw02y8zpvqf0glr4i8522kxpvhsiacb1v1xh04";
+  };
+}

From b46cb34eed46dab1cb77f00c3d42efce3e075431 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 21 May 2019 21:52:20 +0200
Subject: [PATCH 13/19] tv vim: move jq to overlay

---
 tv/2configs/vim.nix |  9 +--------
 tv/5pkgs/vim/jq.nix | 10 ++++++++++
 2 files changed, 11 insertions(+), 8 deletions(-)
 create mode 100644 tv/5pkgs/vim/jq.nix

diff --git a/tv/2configs/vim.nix b/tv/2configs/vim.nix
index 934704295..234602aa4 100644
--- a/tv/2configs/vim.nix
+++ b/tv/2configs/vim.nix
@@ -16,16 +16,9 @@ let {
   extra-runtimepath = concatMapStringsSep "," (pkg: "${pkg.rtp}") [
     pkgs.tv.vimPlugins.elixir
     pkgs.tv.vimPlugins.fzf
+    pkgs.tv.vimPlugins.jq
     pkgs.vimPlugins.fzfWrapper
     pkgs.vimPlugins.undotree
-    (pkgs.vimUtils.buildVimPlugin {
-      name = "vim-syntax-jq";
-      src = pkgs.fetchgit {
-        url = https://github.com/vito-c/jq.vim;
-        rev = "99d55a300047946a82ecdd7617323a751199ad2d";
-        sha256 = "09c94nah47wx0cr556w61h6pfznxld18pfblc3nv51ivbw7cjqyx";
-      };
-    })
     (pkgs.vimUtils.buildVimPlugin {
       name = "file-line-1.0";
       src = pkgs.fetchgit {
diff --git a/tv/5pkgs/vim/jq.nix b/tv/5pkgs/vim/jq.nix
new file mode 100644
index 000000000..523f49f02
--- /dev/null
+++ b/tv/5pkgs/vim/jq.nix
@@ -0,0 +1,10 @@
+{ pkgs }:
+
+pkgs.vimUtils.buildVimPlugin {
+ name = "vim-syntax-jq";
+ src = pkgs.fetchgit {
+   url = https://github.com/vito-c/jq.vim;
+   rev = "99d55a300047946a82ecdd7617323a751199ad2d";
+   sha256 = "09c94nah47wx0cr556w61h6pfznxld18pfblc3nv51ivbw7cjqyx";
+ };
+}

From be42a7069de8a328a6363282151ea21050745910 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 21 May 2019 21:53:17 +0200
Subject: [PATCH 14/19] tv vim: move file-line to overlay

---
 tv/2configs/vim.nix        |  9 +--------
 tv/5pkgs/vim/file-line.nix | 10 ++++++++++
 2 files changed, 11 insertions(+), 8 deletions(-)
 create mode 100644 tv/5pkgs/vim/file-line.nix

diff --git a/tv/2configs/vim.nix b/tv/2configs/vim.nix
index 234602aa4..657d7a6a6 100644
--- a/tv/2configs/vim.nix
+++ b/tv/2configs/vim.nix
@@ -15,18 +15,11 @@ let {
 
   extra-runtimepath = concatMapStringsSep "," (pkg: "${pkg.rtp}") [
     pkgs.tv.vimPlugins.elixir
+    pkgs.tv.vimPlugins.file-line
     pkgs.tv.vimPlugins.fzf
     pkgs.tv.vimPlugins.jq
     pkgs.vimPlugins.fzfWrapper
     pkgs.vimPlugins.undotree
-    (pkgs.vimUtils.buildVimPlugin {
-      name = "file-line-1.0";
-      src = pkgs.fetchgit {
-        url = git://github.com/bogado/file-line;
-        rev = "refs/tags/1.0";
-        sha256 = "0z47zq9rqh06ny0q8lpcdsraf3lyzn9xvb59nywnarf3nxrk6hx0";
-      };
-    })
     ((rtp: rtp // { inherit rtp; }) (pkgs.writeTextFile (let
       name = "hack";
     in {
diff --git a/tv/5pkgs/vim/file-line.nix b/tv/5pkgs/vim/file-line.nix
new file mode 100644
index 000000000..22597265a
--- /dev/null
+++ b/tv/5pkgs/vim/file-line.nix
@@ -0,0 +1,10 @@
+{ pkgs }:
+
+pkgs.vimUtils.buildVimPlugin {
+  name = "file-line-1.0";
+  src = pkgs.fetchgit {
+    url = git://github.com/bogado/file-line;
+    rev = "refs/tags/1.0";
+    sha256 = "0z47zq9rqh06ny0q8lpcdsraf3lyzn9xvb59nywnarf3nxrk6hx0";
+  };
+}

From ec45998cb5665ae005d366e87b2e04fb935906d4 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 21 May 2019 21:55:28 +0200
Subject: [PATCH 15/19] tv vim: move hack to overlay

---
 tv/2configs/vim.nix   | 44 +----------------------------------------
 tv/5pkgs/vim/hack.nix | 46 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 43 deletions(-)
 create mode 100644 tv/5pkgs/vim/hack.nix

diff --git a/tv/2configs/vim.nix b/tv/2configs/vim.nix
index 657d7a6a6..7419eb674 100644
--- a/tv/2configs/vim.nix
+++ b/tv/2configs/vim.nix
@@ -17,52 +17,10 @@ let {
     pkgs.tv.vimPlugins.elixir
     pkgs.tv.vimPlugins.file-line
     pkgs.tv.vimPlugins.fzf
+    pkgs.tv.vimPlugins.hack
     pkgs.tv.vimPlugins.jq
     pkgs.vimPlugins.fzfWrapper
     pkgs.vimPlugins.undotree
-    ((rtp: rtp // { inherit rtp; }) (pkgs.writeTextFile (let
-      name = "hack";
-    in {
-      name = "vim-color-${name}-1.0.2";
-      destination = "/colors/${name}.vim";
-      text = /* vim */ ''
-        set background=dark
-        hi clear
-        if exists("syntax_on")
-          syntax clear
-        endif
-
-        let colors_name = ${toJSON name}
-
-        hi Normal       ctermbg=235
-        hi Comment      ctermfg=242
-        hi Constant     ctermfg=255
-        hi Identifier   ctermfg=253
-        hi Function     ctermfg=253
-        hi Statement    ctermfg=253
-        hi PreProc      ctermfg=251
-        hi Type         ctermfg=251
-        hi Delimiter    ctermfg=251
-        hi Special      ctermfg=255
-
-        hi Garbage      ctermbg=088
-        hi TabStop      ctermbg=016
-        hi Todo         ctermfg=174 ctermbg=NONE
-
-        hi NixCode      ctermfg=040
-        hi NixData      ctermfg=046
-        hi NixQuote     ctermfg=071
-
-        hi diffNewFile  ctermfg=207
-        hi diffFile     ctermfg=207
-        hi diffLine     ctermfg=207
-        hi diffSubname  ctermfg=207
-        hi diffAdded    ctermfg=010
-        hi diffRemoved  ctermfg=009
-
-        hi Search       cterm=NONE ctermbg=216
-      '';
-    })))
     ((rtp: rtp // { inherit rtp; }) (pkgs.writeTextFile (let
       name = "vim";
     in {
diff --git a/tv/5pkgs/vim/hack.nix b/tv/5pkgs/vim/hack.nix
new file mode 100644
index 000000000..2145cc166
--- /dev/null
+++ b/tv/5pkgs/vim/hack.nix
@@ -0,0 +1,46 @@
+with import <stockholm/lib>;
+{ pkgs }:
+
+(rtp: rtp // { inherit rtp; }) (pkgs.writeTextFile (let
+  name = "hack";
+in {
+  name = "vim-color-${name}-1.0.2";
+  destination = "/colors/${name}.vim";
+  text = /* vim */ ''
+    set background=dark
+    hi clear
+    if exists("syntax_on")
+      syntax clear
+    endif
+
+    let colors_name = ${toJSON name}
+
+    hi Normal       ctermbg=235
+    hi Comment      ctermfg=242
+    hi Constant     ctermfg=255
+    hi Identifier   ctermfg=253
+    hi Function     ctermfg=253
+    hi Statement    ctermfg=253
+    hi PreProc      ctermfg=251
+    hi Type         ctermfg=251
+    hi Delimiter    ctermfg=251
+    hi Special      ctermfg=255
+
+    hi Garbage      ctermbg=088
+    hi TabStop      ctermbg=016
+    hi Todo         ctermfg=174 ctermbg=NONE
+
+    hi NixCode      ctermfg=040
+    hi NixData      ctermfg=046
+    hi NixQuote     ctermfg=071
+
+    hi diffNewFile  ctermfg=207
+    hi diffFile     ctermfg=207
+    hi diffLine     ctermfg=207
+    hi diffSubname  ctermfg=207
+    hi diffAdded    ctermfg=010
+    hi diffRemoved  ctermfg=009
+
+    hi Search       cterm=NONE ctermbg=216
+  '';
+}))

From 9b573a35f24b4d259f909fc191c8123a1aeec7b3 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 21 May 2019 21:56:25 +0200
Subject: [PATCH 16/19] tv vim: move vim to overlay

---
 tv/2configs/vim.nix  | 14 +-------------
 tv/5pkgs/vim/vim.nix | 16 ++++++++++++++++
 2 files changed, 17 insertions(+), 13 deletions(-)
 create mode 100644 tv/5pkgs/vim/vim.nix

diff --git a/tv/2configs/vim.nix b/tv/2configs/vim.nix
index 7419eb674..18b69313f 100644
--- a/tv/2configs/vim.nix
+++ b/tv/2configs/vim.nix
@@ -19,21 +19,9 @@ let {
     pkgs.tv.vimPlugins.fzf
     pkgs.tv.vimPlugins.hack
     pkgs.tv.vimPlugins.jq
+    pkgs.tv.vimPlugins.vim
     pkgs.vimPlugins.fzfWrapper
     pkgs.vimPlugins.undotree
-    ((rtp: rtp // { inherit rtp; }) (pkgs.writeTextFile (let
-      name = "vim";
-    in {
-      name = "vim-syntax-${name}-1.0.0";
-      destination = "/syntax/${name}.vim";
-      text = /* vim */ ''
-        ${concatMapStringsSep "\n" (s: /* vim */ ''
-          syn keyword vimColor${s} ${s}
-            \ containedin=ALLBUT,vimComment,vimLineComment
-          hi vimColor${s} ctermfg=${s}
-        '') (map (i: lpad 3 "0" (toString i)) (range 0 255))}
-      '';
-    })))
     ((rtp: rtp // { inherit rtp; }) (pkgs.writeTextFile (let
       name = "showsyntax";
     in {
diff --git a/tv/5pkgs/vim/vim.nix b/tv/5pkgs/vim/vim.nix
new file mode 100644
index 000000000..216ab6abb
--- /dev/null
+++ b/tv/5pkgs/vim/vim.nix
@@ -0,0 +1,16 @@
+with import <stockholm/lib>;
+{ pkgs }:
+
+(rtp: rtp // { inherit rtp; }) (pkgs.writeTextFile (let
+  name = "vim";
+in {
+  name = "vim-syntax-${name}-1.0.0";
+  destination = "/syntax/${name}.vim";
+  text = /* vim */ ''
+    ${concatMapStringsSep "\n" (s: /* vim */ ''
+      syn keyword vimColor${s} ${s}
+        \ containedin=ALLBUT,vimComment,vimLineComment
+      hi vimColor${s} ctermfg=${s}
+    '') (map (i: lpad 3 "0" (toString i)) (range 0 255))}
+  '';
+}))

From 35dcd45cd5245b7976ce68d63cbf0510f432808e Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 21 May 2019 21:57:24 +0200
Subject: [PATCH 17/19] tv vim: move showsyntax to overlay

---
 tv/2configs/vim.nix         | 25 +------------------------
 tv/5pkgs/vim/showsyntax.nix | 26 ++++++++++++++++++++++++++
 2 files changed, 27 insertions(+), 24 deletions(-)
 create mode 100644 tv/5pkgs/vim/showsyntax.nix

diff --git a/tv/2configs/vim.nix b/tv/2configs/vim.nix
index 18b69313f..819578661 100644
--- a/tv/2configs/vim.nix
+++ b/tv/2configs/vim.nix
@@ -19,33 +19,10 @@ let {
     pkgs.tv.vimPlugins.fzf
     pkgs.tv.vimPlugins.hack
     pkgs.tv.vimPlugins.jq
+    pkgs.tv.vimPlugins.showsyntax
     pkgs.tv.vimPlugins.vim
     pkgs.vimPlugins.fzfWrapper
     pkgs.vimPlugins.undotree
-    ((rtp: rtp // { inherit rtp; }) (pkgs.writeTextFile (let
-      name = "showsyntax";
-    in {
-      name = "vim-plugin-${name}-1.0.0";
-      destination = "/plugin/${name}.vim";
-      text = /* vim */ ''
-        if exists('g:loaded_showsyntax')
-          finish
-        endif
-        let g:loaded_showsyntax = 0
-
-        fu! ShowSyntax()
-          let id = synID(line("."), col("."), 1)
-          let name = synIDattr(id, "name")
-          let transName = synIDattr(synIDtrans(id),"name")
-          if name != transName
-            let name .= " (" . transName . ")"
-          endif
-          echo "Syntax: " . name
-        endfu
-
-        command! -n=0 -bar ShowSyntax :call ShowSyntax()
-      '';
-    })))
     ((rtp: rtp // { inherit rtp; }) (pkgs.write "vim-tv" {
       #
       # Haskell
diff --git a/tv/5pkgs/vim/showsyntax.nix b/tv/5pkgs/vim/showsyntax.nix
new file mode 100644
index 000000000..a5547e46a
--- /dev/null
+++ b/tv/5pkgs/vim/showsyntax.nix
@@ -0,0 +1,26 @@
+{ pkgs }:
+
+(rtp: rtp // { inherit rtp; }) (pkgs.writeTextFile (let
+  name = "showsyntax";
+in {
+  name = "vim-plugin-${name}-1.0.0";
+  destination = "/plugin/${name}.vim";
+  text = /* vim */ ''
+    if exists('g:loaded_showsyntax')
+      finish
+    endif
+    let g:loaded_showsyntax = 0
+
+    fu! ShowSyntax()
+      let id = synID(line("."), col("."), 1)
+      let name = synIDattr(id, "name")
+      let transName = synIDattr(synIDtrans(id),"name")
+      if name != transName
+        let name .= " (" . transName . ")"
+      endif
+      echo "Syntax: " . name
+    endfu
+
+    command! -n=0 -bar ShowSyntax :call ShowSyntax()
+  '';
+}))

From 86972b5b600e261f6474f61eaf0c7eb8feb91f55 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 21 May 2019 21:58:16 +0200
Subject: [PATCH 18/19] tv vim: move tv to overlay

---
 tv/2configs/vim.nix | 52 +-------------------------------------------
 tv/5pkgs/vim/tv.nix | 53 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+), 51 deletions(-)
 create mode 100644 tv/5pkgs/vim/tv.nix

diff --git a/tv/2configs/vim.nix b/tv/2configs/vim.nix
index 819578661..b9509bca3 100644
--- a/tv/2configs/vim.nix
+++ b/tv/2configs/vim.nix
@@ -20,60 +20,10 @@ let {
     pkgs.tv.vimPlugins.hack
     pkgs.tv.vimPlugins.jq
     pkgs.tv.vimPlugins.showsyntax
+    pkgs.tv.vimPlugins.tv
     pkgs.tv.vimPlugins.vim
     pkgs.vimPlugins.fzfWrapper
     pkgs.vimPlugins.undotree
-    ((rtp: rtp // { inherit rtp; }) (pkgs.write "vim-tv" {
-      #
-      # Haskell
-      #
-      "/ftplugin/haskell.vim".text = ''
-        if exists("g:vim_tv_ftplugin_haskell_loaded")
-          finish
-        endif
-        let g:vim_tv_ftplugin_haskell_loaded = 1
-
-        setlocal iskeyword+='
-      '';
-      #
-      # TODO
-      #
-      "/ftdetect/todo.vim".text = ''
-        au BufRead,BufNewFile TODO set ft=todo
-      '';
-      "/ftplugin/todo.vim".text = ''
-        setlocal foldmethod=syntax
-      '';
-      "/syntax/todo.vim".text = ''
-        syn match todoComment /#.*/
-
-        syn match todoDate /^[1-9]\S*/
-          \ nextgroup=todoSummary
-
-        syn region todoSummary
-          \ contained
-          \ contains=todoTag
-          \ start="." end="$\n"
-          \ nextgroup=todoBlock
-
-        syn match todoTag /\[[A-Za-z]\+\]/hs=s+1,he=e-1
-          \ contained
-
-        syn region todoBlock
-          \ contained
-          \ contains=Comment
-          \ fold
-          \ start="^[^1-9]" end="^[1-9]"re=s-1,he=s-1,me=s-1
-
-        syn sync minlines=1000
-
-        hi link todoComment Comment
-        hi todoDate ctermfg=255
-        hi todoSummary ctermfg=229
-        hi todoBlock ctermfg=248
-        hi todoTag ctermfg=217
-      '';
-    }))
     ((rtp: rtp // { inherit rtp; }) (pkgs.write "vim-syntax-nix-nested" {
       "/syntax/haskell.vim".text = ''
         syn region String start=+\[[[:alnum:]]*|+ end=+|]+
diff --git a/tv/5pkgs/vim/tv.nix b/tv/5pkgs/vim/tv.nix
new file mode 100644
index 000000000..ae6245b87
--- /dev/null
+++ b/tv/5pkgs/vim/tv.nix
@@ -0,0 +1,53 @@
+{ pkgs }:
+
+(rtp: rtp // { inherit rtp; }) (pkgs.write "vim-tv" {
+  #
+  # Haskell
+  #
+  "/ftplugin/haskell.vim".text = ''
+    if exists("g:vim_tv_ftplugin_haskell_loaded")
+      finish
+    endif
+    let g:vim_tv_ftplugin_haskell_loaded = 1
+
+    setlocal iskeyword+='
+  '';
+  #
+  # TODO
+  #
+  "/ftdetect/todo.vim".text = ''
+    au BufRead,BufNewFile TODO set ft=todo
+  '';
+  "/ftplugin/todo.vim".text = ''
+    setlocal foldmethod=syntax
+  '';
+  "/syntax/todo.vim".text = ''
+    syn match todoComment /#.*/
+
+    syn match todoDate /^[1-9]\S*/
+      \ nextgroup=todoSummary
+
+    syn region todoSummary
+      \ contained
+      \ contains=todoTag
+      \ start="." end="$\n"
+      \ nextgroup=todoBlock
+
+    syn match todoTag /\[[A-Za-z]\+\]/hs=s+1,he=e-1
+      \ contained
+
+    syn region todoBlock
+      \ contained
+      \ contains=Comment
+      \ fold
+      \ start="^[^1-9]" end="^[1-9]"re=s-1,he=s-1,me=s-1
+
+    syn sync minlines=1000
+
+    hi link todoComment Comment
+    hi todoDate ctermfg=255
+    hi todoSummary ctermfg=229
+    hi todoBlock ctermfg=248
+    hi todoTag ctermfg=217
+  '';
+})

From 06f8c8986b01bd805191fa452c09369cdafb0777 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 21 May 2019 21:59:18 +0200
Subject: [PATCH 19/19] tv vim: move nix to overlay

---
 tv/2configs/vim.nix  | 218 +-----------------------------------------
 tv/5pkgs/vim/nix.nix | 222 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 223 insertions(+), 217 deletions(-)
 create mode 100644 tv/5pkgs/vim/nix.nix

diff --git a/tv/2configs/vim.nix b/tv/2configs/vim.nix
index b9509bca3..f8d599f7e 100644
--- a/tv/2configs/vim.nix
+++ b/tv/2configs/vim.nix
@@ -19,228 +19,12 @@ let {
     pkgs.tv.vimPlugins.fzf
     pkgs.tv.vimPlugins.hack
     pkgs.tv.vimPlugins.jq
+    pkgs.tv.vimPlugins.nix
     pkgs.tv.vimPlugins.showsyntax
     pkgs.tv.vimPlugins.tv
     pkgs.tv.vimPlugins.vim
     pkgs.vimPlugins.fzfWrapper
     pkgs.vimPlugins.undotree
-    ((rtp: rtp // { inherit rtp; }) (pkgs.write "vim-syntax-nix-nested" {
-      "/syntax/haskell.vim".text = ''
-        syn region String start=+\[[[:alnum:]]*|+ end=+|]+
-
-        hi link ConId Identifier
-        hi link VarId Identifier
-        hi link hsDelimiter Delimiter
-      '';
-      "/syntax/nix.vim".text = ''
-        "" Quit when a (custom) syntax file was already loaded
-        "if exists("b:current_syntax")
-        "  finish
-        "endif
-
-        "setf nix
-
-        " Ref <nix/src/libexpr/lexer.l>
-        syn match NixID    /[a-zA-Z\_][a-zA-Z0-9\_\'\-]*/
-        syn match NixINT   /\<[0-9]\+\>/
-        syn match NixPATH  /[a-zA-Z0-9\.\_\-\+]*\(\/[a-zA-Z0-9\.\_\-\+]\+\)\+/
-        syn match NixHPATH /\~\(\/[a-zA-Z0-9\.\_\-\+]\+\)\+/
-        syn match NixSPATH /<[a-zA-Z0-9\.\_\-\+]\+\(\/[a-zA-Z0-9\.\_\-\+]\+\)*>/
-        syn match NixURI   /[a-zA-Z][a-zA-Z0-9\+\-\.]*:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']\+/
-        syn region NixSTRING
-          \ matchgroup=NixSTRING
-          \ start='"'
-          \ skip='\\"'
-          \ end='"'
-        syn region NixIND_STRING
-          \ matchgroup=NixIND_STRING
-          \ start="'''"
-          \ skip="'''\('\|[$]\|\\[nrt]\)"
-          \ end="'''"
-
-        syn match NixOther /[-!+&<>|():/;=.,?\[\]*@]/
-
-        syn match NixCommentMatch /\(^\|\s\)#.*/
-        syn region NixCommentRegion start="/\*" end="\*/"
-
-        hi link NixCode Statement
-        hi link NixData Constant
-        hi link NixComment Comment
-
-        hi link NixCommentMatch NixComment
-        hi link NixCommentRegion NixComment
-        hi link NixID NixCode
-        hi link NixINT NixData
-        hi link NixPATH NixData
-        hi link NixHPATH NixData
-        hi link NixSPATH NixData
-        hi link NixURI NixData
-        hi link NixSTRING NixData
-        hi link NixIND_STRING NixData
-
-        hi link NixEnter NixCode
-        hi link NixOther NixCode
-        hi link NixQuote NixData
-
-        syn cluster nix_has_dollar_curly contains=@nix_ind_strings,@nix_strings
-        syn cluster nix_ind_strings contains=NixIND_STRING
-        syn cluster nix_strings contains=NixSTRING
-
-        ${concatStringsSep "\n" (mapAttrsToList (name: {
-          extraStart ? null,
-          lang ? name
-        }:
-        let
-          startAlts = filter isString [
-            ''/\* ${name} \*/''
-            extraStart
-          ];
-          sigil = ''\(${concatStringsSep ''\|'' startAlts}\)[ \t\r\n]*'';
-        in /* vim */ ''
-          syn include @nix_${lang}_syntax syntax/${lang}.vim
-          if exists("b:current_syntax")
-            unlet b:current_syntax
-          endif
-
-          syn match nix_${lang}_sigil
-            \ X${replaceStrings ["X"] ["\\X"] sigil}\ze\('''\|"\)X
-            \ nextgroup=nix_${lang}_region_IND_STRING,nix_${lang}_region_STRING
-            \ transparent
-
-          syn region nix_${lang}_region_STRING
-            \ matchgroup=NixSTRING
-            \ start='"'
-            \ skip='\\"'
-            \ end='"'
-            \ contained
-            \ contains=@nix_${lang}_syntax
-            \ transparent
-
-          syn region nix_${lang}_region_IND_STRING
-            \ matchgroup=NixIND_STRING
-            \ start="'''"
-            \ skip="'''\('\|[$]\|\\[nrt]\)"
-            \ end="'''"
-            \ contained
-            \ contains=@nix_${lang}_syntax
-            \ transparent
-
-          syn cluster nix_ind_strings
-            \ add=nix_${lang}_region_IND_STRING
-
-          syn cluster nix_strings
-            \ add=nix_${lang}_region_STRING
-
-          " This is required because containedin isn't transitive.
-          syn cluster nix_has_dollar_curly
-            \ add=@nix_${lang}_syntax
-        '') (let
-
-          capitalize = s: let
-            xs = stringToCharacters s;
-          in
-            toUpper (head xs) + concatStrings (tail xs);
-
-          alts = xs: ''\(${concatStringsSep ''\|'' xs}\)'';
-          def = k: ''${k}[ \t\r\n]*='';
-          writer = k: ''write${k}[^ \t\r\n]*[ \t\r\n]*\("[^"]*"\|[a-z]\+\)'';
-
-          writerExt = k: writerName ''[^"]*\.${k}'';
-          writerName = k: ''write[^ \t\r\n]*[ \t\r\n]*"${k}"'';
-
-        in {
-          c = {};
-          cabal = {};
-          diff = {};
-          haskell = {};
-          jq.extraStart = alts [
-            (writer "Jq")
-            (writerExt "jq")
-          ];
-          javascript.extraStart = ''/\* js \*/'';
-          lua = {};
-          python.extraStart = ''/\* py \*/'';
-          sed.extraStart = writer "Sed";
-          sh.extraStart = let
-            phases = [
-              "unpack"
-              "patch"
-              "configure"
-              "build"
-              "check"
-              "install"
-              "fixup"
-              "installCheck"
-              "dist"
-            ];
-            shells = [
-              "ash"
-              "bash"
-              "dash"
-            ];
-          in alts [
-            (def "shellHook")
-            (def "${alts phases}Phase")
-            (def "${alts ["pre" "post"]}${alts (map capitalize phases)}")
-            (writer (alts (map capitalize shells)))
-          ];
-          yaml = {};
-          vim.extraStart = alts [
-            (def ''"[^"]*\.vim"\.text'')
-            (writerExt "vim")
-            (writerName ''\([^"]*\.\)\?vimrc'')
-          ];
-          xdefaults = {};
-          xmodmap = {};
-        }))}
-
-        " Clear syntax that interferes with nixINSIDE_DOLLAR_CURLY.
-        syn clear shVarAssign
-
-        syn region nixINSIDE_DOLLAR_CURLY
-          \ matchgroup=NixEnter
-          \ start="[$]{"
-          \ end="}"
-          \ contains=TOP
-          \ containedin=@nix_has_dollar_curly
-          \ transparent
-
-        syn region nix_inside_curly
-          \ matchgroup=NixEnter
-          \ start="{"
-          \ end="}"
-          \ contains=TOP
-          \ containedin=nixINSIDE_DOLLAR_CURLY,nix_inside_curly
-          \ transparent
-
-        syn match NixQuote /'''\(''$\|\\.\)/he=s+2
-          \ containedin=@nix_ind_strings
-          \ contained
-
-        syn match NixQuote /'''\('\|\\.\)/he=s+1
-          \ containedin=@nix_ind_strings
-          \ contained
-
-        syn match NixQuote /\\./he=s+1
-          \ containedin=@nix_strings
-          \ contained
-
-        syn sync fromstart
-
-        let b:current_syntax = "nix"
-
-        set isk=@,48-57,_,192-255,-,'
-      '';
-      "/syntax/sed.vim".text = ''
-        syn region sedBranch
-          \ matchgroup=sedFunction start="T"
-          \ matchgroup=sedSemicolon end=";\|$"
-          \ contains=sedWhitespace
-      '';
-      "/syntax/xmodmap.vim".text = ''
-        syn match xmodmapComment /^\s*!.*/
-      '';
-    }))
   ];
 
   dirs = {
diff --git a/tv/5pkgs/vim/nix.nix b/tv/5pkgs/vim/nix.nix
new file mode 100644
index 000000000..a58a45b2d
--- /dev/null
+++ b/tv/5pkgs/vim/nix.nix
@@ -0,0 +1,222 @@
+with import <stockholm/lib>;
+{ pkgs }:
+
+(rtp: rtp // { inherit rtp; }) (pkgs.write "vim-syntax-nix-nested" {
+  "/syntax/haskell.vim".text = ''
+    syn region String start=+\[[[:alnum:]]*|+ end=+|]+
+
+    hi link ConId Identifier
+    hi link VarId Identifier
+    hi link hsDelimiter Delimiter
+  '';
+  "/syntax/nix.vim".text = ''
+    "" Quit when a (custom) syntax file was already loaded
+    "if exists("b:current_syntax")
+    "  finish
+    "endif
+
+    "setf nix
+
+    " Ref <nix/src/libexpr/lexer.l>
+    syn match NixID    /[a-zA-Z\_][a-zA-Z0-9\_\'\-]*/
+    syn match NixINT   /\<[0-9]\+\>/
+    syn match NixPATH  /[a-zA-Z0-9\.\_\-\+]*\(\/[a-zA-Z0-9\.\_\-\+]\+\)\+/
+    syn match NixHPATH /\~\(\/[a-zA-Z0-9\.\_\-\+]\+\)\+/
+    syn match NixSPATH /<[a-zA-Z0-9\.\_\-\+]\+\(\/[a-zA-Z0-9\.\_\-\+]\+\)*>/
+    syn match NixURI   /[a-zA-Z][a-zA-Z0-9\+\-\.]*:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']\+/
+    syn region NixSTRING
+      \ matchgroup=NixSTRING
+      \ start='"'
+      \ skip='\\"'
+      \ end='"'
+    syn region NixIND_STRING
+      \ matchgroup=NixIND_STRING
+      \ start="'''"
+      \ skip="'''\('\|[$]\|\\[nrt]\)"
+      \ end="'''"
+
+    syn match NixOther /[-!+&<>|():/;=.,?\[\]*@]/
+
+    syn match NixCommentMatch /\(^\|\s\)#.*/
+    syn region NixCommentRegion start="/\*" end="\*/"
+
+    hi link NixCode Statement
+    hi link NixData Constant
+    hi link NixComment Comment
+
+    hi link NixCommentMatch NixComment
+    hi link NixCommentRegion NixComment
+    hi link NixID NixCode
+    hi link NixINT NixData
+    hi link NixPATH NixData
+    hi link NixHPATH NixData
+    hi link NixSPATH NixData
+    hi link NixURI NixData
+    hi link NixSTRING NixData
+    hi link NixIND_STRING NixData
+
+    hi link NixEnter NixCode
+    hi link NixOther NixCode
+    hi link NixQuote NixData
+
+    syn cluster nix_has_dollar_curly contains=@nix_ind_strings,@nix_strings
+    syn cluster nix_ind_strings contains=NixIND_STRING
+    syn cluster nix_strings contains=NixSTRING
+
+    ${concatStringsSep "\n" (mapAttrsToList (name: {
+      extraStart ? null,
+      lang ? name
+    }:
+    let
+      startAlts = filter isString [
+        ''/\* ${name} \*/''
+        extraStart
+      ];
+      sigil = ''\(${concatStringsSep ''\|'' startAlts}\)[ \t\r\n]*'';
+    in /* vim */ ''
+      syn include @nix_${lang}_syntax syntax/${lang}.vim
+      if exists("b:current_syntax")
+        unlet b:current_syntax
+      endif
+
+      syn match nix_${lang}_sigil
+        \ X${replaceStrings ["X"] ["\\X"] sigil}\ze\('''\|"\)X
+        \ nextgroup=nix_${lang}_region_IND_STRING,nix_${lang}_region_STRING
+        \ transparent
+
+      syn region nix_${lang}_region_STRING
+        \ matchgroup=NixSTRING
+        \ start='"'
+        \ skip='\\"'
+        \ end='"'
+        \ contained
+        \ contains=@nix_${lang}_syntax
+        \ transparent
+
+      syn region nix_${lang}_region_IND_STRING
+        \ matchgroup=NixIND_STRING
+        \ start="'''"
+        \ skip="'''\('\|[$]\|\\[nrt]\)"
+        \ end="'''"
+        \ contained
+        \ contains=@nix_${lang}_syntax
+        \ transparent
+
+      syn cluster nix_ind_strings
+        \ add=nix_${lang}_region_IND_STRING
+
+      syn cluster nix_strings
+        \ add=nix_${lang}_region_STRING
+
+      " This is required because containedin isn't transitive.
+      syn cluster nix_has_dollar_curly
+        \ add=@nix_${lang}_syntax
+    '') (let
+
+      # TODO move this higher
+      capitalize = s: let
+        xs = stringToCharacters s;
+      in
+        toUpper (head xs) + concatStrings (tail xs);
+
+      alts = xs: ''\(${concatStringsSep ''\|'' xs}\)'';
+      def = k: ''${k}[ \t\r\n]*='';
+      writer = k: ''write${k}[^ \t\r\n]*[ \t\r\n]*\("[^"]*"\|[a-z]\+\)'';
+
+      writerExt = k: writerName ''[^"]*\.${k}'';
+      writerName = k: ''write[^ \t\r\n]*[ \t\r\n]*"${k}"'';
+
+    in {
+      c = {};
+      cabal = {};
+      diff = {};
+      haskell = {};
+      jq.extraStart = alts [
+        (writer "Jq")
+        (writerExt "jq")
+      ];
+      javascript.extraStart = ''/\* js \*/'';
+      lua = {};
+      #nginx = {};
+      python.extraStart = ''/\* py \*/'';
+      sed.extraStart = writer "Sed";
+      sh.extraStart = let
+        phases = [
+          "unpack"
+          "patch"
+          "configure"
+          "build"
+          "check"
+          "install"
+          "fixup"
+          "installCheck"
+          "dist"
+        ];
+        shells = [
+          "ash"
+          "bash"
+          "dash"
+        ];
+      in alts [
+        (def "shellHook")
+        (def "${alts phases}Phase")
+        (def "${alts ["pre" "post"]}${alts (map capitalize phases)}")
+        (writer (alts (map capitalize shells)))
+      ];
+      yaml = {};
+      vim.extraStart = alts [
+        (def ''"[^"]*\.vim"\.text'')
+        (writerExt "vim")
+        (writerName ''\([^"]*\.\)\?vimrc'')
+      ];
+      xdefaults = {};
+      xmodmap = {};
+    }))}
+
+    " Clear syntax that interferes with nixINSIDE_DOLLAR_CURLY.
+    syn clear shVarAssign
+
+    syn region nixINSIDE_DOLLAR_CURLY
+      \ matchgroup=NixEnter
+      \ start="[$]{"
+      \ end="}"
+      \ contains=TOP
+      \ containedin=@nix_has_dollar_curly
+      \ transparent
+
+    syn region nix_inside_curly
+      \ matchgroup=NixEnter
+      \ start="{"
+      \ end="}"
+      \ contains=TOP
+      \ containedin=nixINSIDE_DOLLAR_CURLY,nix_inside_curly
+      \ transparent
+
+    syn match NixQuote /'''\(''$\|\\.\)/he=s+2
+      \ containedin=@nix_ind_strings
+      \ contained
+
+    syn match NixQuote /'''\('\|\\.\)/he=s+1
+      \ containedin=@nix_ind_strings
+      \ contained
+
+    syn match NixQuote /\\./he=s+1
+      \ containedin=@nix_strings
+      \ contained
+
+    syn sync fromstart
+
+    let b:current_syntax = "nix"
+
+    set isk=@,48-57,_,192-255,-,'
+  '';
+  "/syntax/sed.vim".text = ''
+    syn region sedBranch
+      \ matchgroup=sedFunction start="T"
+      \ matchgroup=sedSemicolon end=";\|$"
+      \ contains=sedWhitespace
+  '';
+  "/syntax/xmodmap.vim".text = ''
+    syn match xmodmapComment /^\s*!.*/
+  '';
+})