about summary refs log tree commit diff
path: root/pkgs/profpatsch
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/profpatsch')
-rw-r--r--pkgs/profpatsch/default.nix94
-rw-r--r--pkgs/profpatsch/display-infos/default.nix50
-rw-r--r--pkgs/profpatsch/execline/escape.nix30
-rw-r--r--pkgs/profpatsch/execline/run-execline-tests.nix82
-rw-r--r--pkgs/profpatsch/execline/run-execline.nix19
-rw-r--r--pkgs/profpatsch/execline/symlink.nix48
-rw-r--r--pkgs/profpatsch/nman/default.nix4
-rw-r--r--pkgs/profpatsch/sfttime/default.nix14
-rwxr-xr-xpkgs/profpatsch/sfttime/sfttime.sh145
-rw-r--r--pkgs/profpatsch/utils-hs/default.nix14
-rw-r--r--pkgs/profpatsch/xmonad/DhallTypedInput.hs232
11 files changed, 622 insertions, 110 deletions
diff --git a/pkgs/profpatsch/default.nix b/pkgs/profpatsch/default.nix
index a4378ecf..dc746c2e 100644
--- a/pkgs/profpatsch/default.nix
+++ b/pkgs/profpatsch/default.nix
@@ -5,11 +5,25 @@ let
 
   # wrapper for execlineb that doesn’t need the execline commands
   # in PATH to work (making them appear like “builtins”)
+  # TODO: upstream into nixpkgs
+  # TODO: the grep could be nicer
   execlineb-with-builtins =
     let eldir = "${pkgs.execline}/bin";
     in pkgs.writeScriptBin "execlineb" ''
       #!${eldir}/execlineb -s0
+      # appends the execlineb bin dir to PATH if not yet in PATH
       ${eldir}/define eldir ${eldir}
+      ''${eldir}/ifelse
+      {
+        # since this is nix, we can grep for the execline drv hash in PATH
+        # to see whether it’s already in there
+        ''${eldir}/pipeline
+        { ${pkgs.coreutils}/bin/printenv PATH }
+        ${pkgs.gnugrep}/bin/grep --quiet "${eldir}"
+      }
+      # it’s there already
+      { ''${eldir}/execlineb $@ }
+      # not there yet, add it
       ''${eldir}/importas oldpath PATH
       ''${eldir}/export PATH "''${eldir}:''${oldpath}"
       ''${eldir}/execlineb $@
@@ -46,6 +60,52 @@ let
       allowSubstitutes = false;
     }) cmd;
 
+  testing = import ./testing {
+    inherit stdenv lib;
+    inherit (runExeclineFns) runExecline;
+    inherit (pkgs) runCommand;
+    bin = bins pkgs.s6PortableUtils [ "s6-touch" "s6-echo" ];
+  };
+
+  runExeclineFns =
+    # todo: factor out calling tests
+    let
+      it = import ./execline/run-execline.nix {
+        bin = (bins execlineb-with-builtins [ "execlineb" ])
+           // (bins pkgs.execline [ "redirfd" "importas" "exec" ]);
+        inherit stdenv lib;
+      };
+      itLocal = name: args: execline:
+        it name (args // {
+          derivationArgs = args.derivationArgs or {} // {
+            preferLocalBuild = true;
+            allowSubstitutes = false;
+          };
+        }) execline;
+
+      tests = import ./execline/run-execline-tests.nix {
+        # can’t use runExeclineLocal in the tests,
+        # because it is tested by the tests (well, it does
+        # work, but then you have to run the tests every time)
+        runExecline = it;
+        inherit (testing) drvSeqL;
+        inherit (pkgs) coreutils;
+        inherit stdenv;
+        bin = (bins execlineb-with-builtins [ "execlineb" ])
+           // (bins pkgs.execline [
+                 { use = "if"; as = "execlineIf"; }
+                 "redirfd" "importas"
+               ])
+           // (bins pkgs.s6PortableUtils
+                [ "s6-cat" "s6-grep" "s6-touch" "s6-test" "s6-chmod" ]);
+       };
+    in {
+      runExecline = it;
+      runExeclineLocal = name: args: execline:
+        testing.drvSeqL tests (itLocal name args execline);
+    };
+
+
 in rec {
   inherit (nixperiments)
     # filterSource by parsing a .gitignore file
@@ -60,10 +120,11 @@ in rec {
     json2json json2string;
 
   backlight = callPackage ./backlight { inherit (pkgs.xorg) xbacklight; };
-  display-infos = callPackage ./display-infos {};
+  display-infos = callPackage ./display-infos { inherit sfttime; };
   git-commit-index = callPackage ./git-commit-index { inherit script runCommandLocal; };
   nix-http-serve = callPackage ./nix-http-serve {};
   nman = callPackage ./nman {};
+  sfttime = callPackage ./sfttime {};
   show-qr-code = callPackage ./show-qr-code {};
   warpspeed = callPackage ./warpspeed {
     inherit (pkgs.haskellPackages) ghcWithPackages;
@@ -90,35 +151,8 @@ in rec {
     ];
   });
 
-  runExecline =
-    # todo: factor out calling tests
-    let
-      it = import ./execline/run-execline.nix {
-        bin = (bins execlineb-with-builtins [ "execlineb" ])
-           // (bins pkgs.execline [ "redirfd" "importas" "exec" ]);
-        inherit stdenv;
-      };
-      tests = import ./execline/run-execline-tests.nix {
-        runExecline = it;
-        inherit (testing) drvSeqL;
-        inherit (pkgs) coreutils;
-        inherit stdenv;
-        bin = (bins execlineb-with-builtins [ "execlineb" ])
-           // (bins pkgs.execline [
-                 { use = "if"; as = "execlineIf"; }
-                 "redirfd" "importas"
-               ])
-           // (bins pkgs.s6PortableUtils
-                [ "s6-cat" "s6-grep" "s6-touch" "s6-test" "s6-chmod" ]);
-       };
-    in tests;
-
-
-  testing = import ./testing {
-    inherit stdenv lib runExecline;
-    inherit (pkgs) runCommand;
-    bin = bins pkgs.s6PortableUtils [ "s6-touch" "s6-echo" ];
-  };
+  inherit (runExeclineFns)
+    runExecline runExeclineLocal;
 
   symlink = pkgs.callPackage ./execline/symlink.nix {
     inherit runExecline;
diff --git a/pkgs/profpatsch/display-infos/default.nix b/pkgs/profpatsch/display-infos/default.nix
index d213241c..b626e844 100644
--- a/pkgs/profpatsch/display-infos/default.nix
+++ b/pkgs/profpatsch/display-infos/default.nix
@@ -1,8 +1,8 @@
-{ lib, runCommand, python3, libnotify }:
+{ lib, runCommand, writeText, python3, libnotify, bc, sfttime }:
 
 let
   name = "display-infos-0.1.0";
-  script = builtins.toFile (name + "-script") ''
+  script = writeText (name + "-script") ''
     #!@python3@
 
     import sys
@@ -11,20 +11,53 @@ let
     import os.path as path
     import statistics as st
 
+    def readint(fn):
+        with open(fn, 'r') as f:
+            return int(f.read())
+
+    def seconds_to_sft(secs):
+        p = sub.Popen(["@bc@", "-l"], stdin=sub.PIPE, stdout=sub.PIPE)
+        (sft, _) = p.communicate(input="scale=2; obase=16; {} / 86400\n".format(secs).encode())
+        p.terminate()
+        return str(sft.strip().decode())
+
+    charging = readint("/sys/class/power_supply/AC/online")
+
     full = 0
     now  = 0
+    # this is "to charged" if charging and "to empty" if not
+    seconds_remaining = 0
     for bat in glob.iglob("/sys/class/power_supply/BAT*"):
-        def readint(fn):
-            with open(fn, 'r') as f:
-                return int(f.read())
 
+        # these files might be different for different ACPI/battery providers
+        # see the full list in acpi.c of the acpi(1) tool
+        # unit: who knows
         full += readint(path.join(bat, "energy_full"))
         now  += readint(path.join(bat, "energy_now" ))
+        # in unit?/hours, hopefully the same unit as above
+        # ACPI is a garbage fire
+        current_rate = readint(path.join(bat, "power_now"))
+
+        if current_rate == 0:
+          continue
+        elif charging:
+          seconds_remaining += 3600 * (full - now) / current_rate
+        else:
+          seconds_remaining += 3600 * now / current_rate
 
     bat = round( now/full, 2 )
+    ac = "🗲 " if charging else ""
+    sft_remaining = seconds_to_sft(seconds_remaining)
     date = sub.run(["date", "+%d.%m. %a %T"], stdout=sub.PIPE).stdout.strip().decode()
-    notify = "BAT: {}% | {}".format(int(bat*100), date)
-    sub.run(["@notify-send@", notify])
+    sftdate = sub.run(["@sfttime@"], stdout=sub.PIPE).stdout.strip().decode()
+    notify = "BAT: {percent}% {ac}{charge}| {date} | {sftdate}".format(
+      percent = int(bat*100),
+      ac = ac,
+      charge = "{} ".format(sft_remaining) if seconds_remaining else "",
+      date = date,
+      sftdate = sftdate
+    )
+    print(notify)
   '';
 
 in
@@ -33,6 +66,7 @@ in
   } ''
     substitute ${script} script \
       --replace "@python3@" "${getBin python3}/bin/python3" \
-      --replace "@notify-send@" "${getBin libnotify}/bin/notify-send"
+      --replace "@bc@" "${getBin bc}/bin/bc" \
+      --replace "@sfttime@" "${getBin sfttime}/bin/sfttime"
     install -D script $out/bin/display-infos
   ''
diff --git a/pkgs/profpatsch/execline/escape.nix b/pkgs/profpatsch/execline/escape.nix
new file mode 100644
index 00000000..d9a0be0c
--- /dev/null
+++ b/pkgs/profpatsch/execline/escape.nix
@@ -0,0 +1,30 @@
+{ lib }:
+let
+  # replaces " and \ to \" and \\ respectively and quote with "
+  # e.g.
+  #   a"b\c -> "a\"b\\c"
+  #   a\"bc -> "a\\\"bc"
+  # TODO upsteam into nixpkgs
+  escapeExeclineArg = arg:
+    ''"${builtins.replaceStrings [ ''"'' ''\'' ] [ ''\"'' ''\\'' ] (toString arg)}"'';
+
+  # Escapes an execline (list of execline strings) to be passed to execlineb
+  # Give it a nested list of strings. Nested lists are interpolated as execline
+  # blocks ({}).
+  # Everything is quoted correctly.
+  #
+  # Example:
+  #   escapeExecline [ "if" [ "somecommand" ] "true" ]
+  #   == ''"if" { "somecommand" } "true"''
+  escapeExecline = execlineList: lib.concatStringsSep " "
+    (let
+      go = arg:
+        if      builtins.isString arg then [(escapeExeclineArg arg)]
+        else if lib.isDerivation arg then [(escapeExeclineArg arg)]
+        else if builtins.isList arg then [ "{" ] ++ builtins.concatMap go arg ++ [ "}" ]
+        else abort "escapeExecline can only hande nested lists of strings, was ${lib.generators.toPretty {} arg}";
+     in builtins.concatMap go execlineList);
+
+in {
+  inherit escapeExecline;
+}
diff --git a/pkgs/profpatsch/execline/run-execline-tests.nix b/pkgs/profpatsch/execline/run-execline-tests.nix
index ebfdeb20..c3f534cc 100644
--- a/pkgs/profpatsch/execline/run-execline-tests.nix
+++ b/pkgs/profpatsch/execline/run-execline-tests.nix
@@ -2,26 +2,24 @@
 # https://www.mail-archive.com/skaware@list.skarnet.org/msg01256.html
 , coreutils }:
 
-# TODO: run all of these locally! runExeclineLocal
-
 let
 
   # lol
-  writeScript = name: script: runExecline {
-    inherit name;
+  writeScript = name: script: runExecline name {
     derivationArgs = {
       inherit script;
       passAsFile = [ "script" ];
+      preferLocalBuild = true;
+      allowSubstitutes = false;
     };
-    execline = ''
-      importas -ui s scriptPath
-      importas -ui out out
-      foreground {
-        ${coreutils}/bin/mv $s $out
-      }
-      ${bin.s6-chmod} 0755 $out
-    '';
-   };
+  } [
+      "importas" "-ui" "s" "scriptPath"
+      "importas" "-ui" "out" "out"
+      "foreground" [
+        "${coreutils}/bin/mv" "$s" "$out"
+      ]
+      "${bin.s6-chmod}" "0755" "$out"
+  ];
 
   # execline block of depth 1
   block = args: builtins.map (arg: " ${arg}") args ++ [ "" ];
@@ -30,7 +28,7 @@ let
   # in the given file. Does not use runExecline, because
   # that should be tested after all.
   fileHasLine = line: file: derivation {
-    name = "file-${file.name}-has-line";
+    name = "run-execline-test-file-${file.name}-has-line";
     inherit (stdenv) system;
     builder = bin.execlineIf;
     args =
@@ -43,41 +41,49 @@ let
         bin.importas "-ui" "out" "out"
         bin.s6-touch "$out"
       ];
+    preferLocalBuild = true;
+    allowSubstitutes = false;
   };
 
   # basic test that touches out
-  basic = runExecline {
-    name = "basic";
-    execline = ''
-      importas -ui out out
-      ${bin.s6-touch} $out
-    '';
-  };
+  basic = runExecline "run-execline-test-basic" {
+    derivationArgs = {
+      preferLocalBuild = true;
+      allowSubstitutes = false;
+    };
+  } [
+      "importas" "-ui" "out" "out"
+      "${bin.s6-touch}" "$out"
+  ];
 
   # whether the stdin argument works as intended
-  stdin = fileHasLine "foo" (runExecline {
-    name = "stdin";
+  stdin = fileHasLine "foo" (runExecline "run-execline-test-stdin" {
     stdin = "foo\nbar\nfoo";
-    execline = ''
-      importas -ui out out
+    derivationArgs = {
+      preferLocalBuild = true;
+      allowSubstitutes = false;
+    };
+  } [
+      "importas" "-ui" "out" "out"
       # this pipes stdout of s6-cat to $out
       # and s6-cat redirects from stdin to stdout
-      redirfd -w 1 $out ${bin.s6-cat}
-    '';
-  });
+      "redirfd" "-w" "1" "$out" bin.s6-cat
+  ]);
 
-  wrapWithVar = runExecline {
-    name = "wrap-with-var";
+  wrapWithVar = runExecline "run-execline-test-wrap-with-var" {
     builderWrapper = writeScript "var-wrapper" ''
       #!${bin.execlineb} -S0
       export myvar myvalue $@
     '';
-    execline = ''
-      importas -ui v myvar
-      if { ${bin.s6-test} myvalue = $v }
-        importas out out
-        ${bin.s6-touch} $out
-    '';
-  };
+    derivationArgs = {
+      preferLocalBuild = true;
+      allowSubstitutes = false;
+    };
+  } [
+    "importas" "-ui" "v" "myvar"
+    "if" [ bin.s6-test "myvalue" "=" "$v" ]
+      "importas" "out" "out"
+      bin.s6-touch "$out"
+  ];
 
-in args: drvSeqL [ basic stdin wrapWithVar ] (runExecline args)
+in [ basic stdin wrapWithVar ]
diff --git a/pkgs/profpatsch/execline/run-execline.nix b/pkgs/profpatsch/execline/run-execline.nix
index dbc6f4fd..2efe43d6 100644
--- a/pkgs/profpatsch/execline/run-execline.nix
+++ b/pkgs/profpatsch/execline/run-execline.nix
@@ -1,15 +1,18 @@
-{ stdenv, bin }:
-{ name
-# the execline script as string
-, execline
+{ stdenv, bin, lib }:
+name:
+{
 # a string to pass as stdin to the execline script
-, stdin ? ""
+stdin ? ""
 # a program wrapping the acutal execline invocation;
 # should be in Bernstein-chaining style
 , builderWrapper ? bin.exec
 # additional arguments to pass to the derivation
 , derivationArgs ? {}
 }:
+# the execline script as a nested list of string,
+# representing the blocks;
+# see docs of `escapeExecline`.
+ execline:
 
 # those arguments can’t be overwritten
 assert !derivationArgs ? system;
@@ -18,6 +21,7 @@ assert !derivationArgs ? builder;
 assert !derivationArgs ? args;
 
 derivation (derivationArgs // {
+  # TODO: what about cross?
   inherit (stdenv) system;
   inherit name;
 
@@ -26,7 +30,10 @@ derivation (derivationArgs // {
   # to pass the script and stdin as envvar;
   # this might clash with another passed envar,
   # so we give it a long & unique name
-  _runExeclineScript = execline;
+  _runExeclineScript =
+    let
+      escape = (import ./escape.nix { inherit lib; });
+    in escape.escapeExecline execline;
   _runExeclineStdin = stdin;
   passAsFile = [
     "_runExeclineScript"
diff --git a/pkgs/profpatsch/execline/symlink.nix b/pkgs/profpatsch/execline/symlink.nix
index ca8684d2..c6a311d8 100644
--- a/pkgs/profpatsch/execline/symlink.nix
+++ b/pkgs/profpatsch/execline/symlink.nix
@@ -11,9 +11,7 @@ let
     "${toString (builtins.stringLength s)}:${s},";
 
 in
-runExecline {
-  inherit name;
-
+runExecline name {
   derivationArgs = {
     pathTuples = lib.concatMapStrings
       ({dest, orig}: toNetstring
@@ -23,28 +21,26 @@ runExecline {
     # bah! coreutils just for cat :(
     PATH = lib.makeBinPath [ s6-portable-utils ];
   };
+} [
+  "importas" "-ui" "p" "pathTuplesPath"
+  "importas" "-ui" "out" "out"
+  "forbacktickx" "-d" "" "destorig" [ "${coreutils}/bin/cat" "$p" ]
+    "importas" "-ui" "do" "destorig"
+    "multidefine" "-d" "" "$do" [ "destsuffix" "orig" ]
+    "define" "dest" ''''${out}/''${destsuffix}''
 
-  execline = ''
-    importas -ui p pathTuplesPath
-    importas -ui out out
-    forbacktickx -d "" destorig { ${coreutils}/bin/cat $p }
-      importas -ui do destorig
-      multidefine -d "" $do { destsuffix orig }
-      define dest ''${out}/''${destsuffix}
-
-      # this call happens for every file, not very efficient
-      foreground {
-        backtick -n d { s6-dirname $dest }
-        importas -ui d d
-        s6-mkdir -p $d
-      }
+    # this call happens for every file, not very efficient
+    "foreground" [
+      "backtick" "-n" "d" [ "s6-dirname" "$dest" ]
+      "importas" "-ui" "d" "d"
+      "s6-mkdir" "-p" "$d"
+    ]
 
-      ifthenelse { s6-test -L $orig } {
-        backtick -n res { s6-linkname -f $orig }
-        importas -ui res res
-        s6-ln -fs $res $dest
-      } {
-        s6-ln -fs $orig $dest
-      }
-  '';
-}
+    "ifthenelse" [ "s6-test" "-L" "$orig" ] [
+      "backtick" "-n" "res" [ "s6-linkname" "-f" "$orig" ]
+      "importas" "-ui" "res" "res"
+      "s6-ln" "-fs" "$res" "$dest"
+    ] [
+      "s6-ln" "-fs" "$orig" "$dest"
+    ]
+]
diff --git a/pkgs/profpatsch/nman/default.nix b/pkgs/profpatsch/nman/default.nix
index b9b967cf..bbf4f00f 100644
--- a/pkgs/profpatsch/nman/default.nix
+++ b/pkgs/profpatsch/nman/default.nix
@@ -6,7 +6,9 @@ runCommandNoCC "nman" {
     license = licenses.gpl3;
   };
 } ''
-    ${lib.getBin go}/bin/go build -o nman ${./nman.go}
+    mkdir cache
+    env GOCACHE="$PWD/cache" \
+      ${lib.getBin go}/bin/go build -o nman ${./nman.go}
     install -D nman $out/bin/nman
 ''
 
diff --git a/pkgs/profpatsch/sfttime/default.nix b/pkgs/profpatsch/sfttime/default.nix
new file mode 100644
index 00000000..29d9170b
--- /dev/null
+++ b/pkgs/profpatsch/sfttime/default.nix
@@ -0,0 +1,14 @@
+{ stdenv, makeWrapper, bc }:
+
+stdenv.mkDerivation {
+  name = "sfttime";
+
+  phases = [ "installPhase" "fixupPhase" ];
+  buildInputs = [ makeWrapper ];
+
+  installPhase = ''
+    install -D ${./sfttime.sh} $out/bin/sfttime
+    wrapProgram $out/bin/sfttime \
+      --prefix PATH : ${stdenv.lib.makeBinPath [ bc ]}
+  '';
+}
diff --git a/pkgs/profpatsch/sfttime/sfttime.sh b/pkgs/profpatsch/sfttime/sfttime.sh
new file mode 100755
index 00000000..949341b7
--- /dev/null
+++ b/pkgs/profpatsch/sfttime/sfttime.sh
@@ -0,0 +1,145 @@
+#!/usr/bin/env bash
+# this script was created in 3BBE.81[sft].
+# usage:
+# to convert to sfttime:
+#	$0 [c date] [digitcount] [nodate]
+#	if date is given, converts the given date to sfttime.
+#	if date is not given, converts the current date to sfttime.
+#	digitcount specifies the accuracy for the time part.
+#	nodate hides the date part.
+# to convert from sfttime:
+#	$0 r sfttime [unix]
+#	converts the given sfttime to 'standard' time.
+#	if 'unix' is provided, the output will be in unix time.
+# to show info about sfttime units
+#	$0 i [[sft]]$num
+#	displays name of unit [sft]$num, as well as it's value
+#	in both days and 'standard' units.
+
+SFT_EPOCH_UNIX=49020
+
+case $1 in
+	"c")
+		unixtime=$(date --date="$2" +%s.%N)
+		shift
+		shift
+		mode=fw
+		;;
+	"r")
+		shift
+		sfttime=$1
+		if [[ $sfttime =~ ^([0-9A-F]*(.[0-9A-F]+)?)(\[[sS][fF][tT]\])?$ ]] && [[ $sfttime ]]; then
+			sfttime=${BASH_REMATCH[1]}
+		else
+			echo "error" 2>&1
+			exit 1
+		fi
+		shift
+		mode=bw
+		;;
+	"i")
+		shift
+		inforeq=$1
+		if [[ $inforeq =~ ^(\[[sS][fF][tT]\])?(-?[0-9]+)$ ]]; then
+			inforeq=${BASH_REMATCH[2]}
+			let inforeq=$inforeq
+			mode=in
+		elif [[ $inforeq =~ ^(\[[sS][fF][tT]\])?[eE][pP][oO][cC][hH]$ ]]; then
+			echo "[sft]epoch:"
+			echo "unix time $SFT_EPOCH_UNIX"
+			echo "1970-01-01 13:37:00 UTC"
+			exit 0
+		else
+			echo "error" 2>&1
+			exit 1
+		fi
+		shift
+		mode=in
+		;;
+	*)
+		unixtime=$(date +%s.%N)
+		mode=fw
+		;;
+esac
+
+case $mode in
+	"fw")
+		sfttime=$(echo "obase=16; ($unixtime-$SFT_EPOCH_UNIX)/86400" | bc -l)
+		if [[ $1 -ge 1 ]]; then
+			digits=$1
+			shift
+		elif [[ ! $1 ]] || [[ $1 == nodate ]]; then
+			digits=3
+		else
+			digits=0
+		fi
+
+		if [[ $sfttime =~ ^([0-9A-F]+)[.]([0-9A-F]{$digits}).*$ ]]; then
+			date=${BASH_REMATCH[1]}
+			time=${BASH_REMATCH[2]}
+		else
+			echo "Error" &1>2
+			exit 1
+		fi
+
+		if [[ $digits -eq 0 ]]; then
+			echo "$date[sft]"
+		else
+			if [[ $1 == nodate ]]; then
+				echo ".$time[sft]"
+				shift
+			else
+				echo "$date.$time[sft]"
+			fi
+		fi
+		;;
+	"bw")
+		unixtime=$(echo "ibase=16; $sfttime*15180+BF7C" | bc -l)
+		case $1 in
+			unix)
+				shift
+				echo $unixtime
+				;;
+			*)
+				date --date="1970-01-01 $unixtime sec"
+				;;
+		esac
+		;;
+	"in")
+		name="[sft]$inforeq"
+		case $inforeq in
+      -4) newname="[sft]tick";;
+			-3)	newname="[sft]tentacle";;
+			-2)	newname="[sft]schinken";;
+			-1)	newname="[sft]major";;
+			0)	newname="day";;
+			1)	newname="[sft]vergil";;
+			2)	newname="[sft]stallman";;
+			3)	newname="[sft]odin";;
+		esac
+		if [[ $newname ]]; then
+			echo "alternative name for $name: $newname"
+			name="$newname"
+		fi
+		one="1 $name"
+		echo "$one after [sft]epoch:"
+		sfttime=$(echo "obase=16; 16^$inforeq" | bc -l)[sft]
+		echo $sfttime
+		echo "time equivalent of $one:"
+		echo "the duration of $(echo 794243384928000*16^$inforeq | bc -l) periods of the radiation corresponding to the transition between the two hyperfine levels of the ground state of the caesium 133 atom"
+
+		echo "standard time units equivalent:"
+		seconds=$(echo "86400*16^$inforeq" | bc -l)
+		if [[ $(echo "$seconds < 60" | bc -l) == 1 ]]; then
+			echo "$seconds seconds"
+		elif [[ $(echo "$seconds < 3600" | bc -l) == 1 ]]; then
+			echo "$(echo $seconds/60 | bc -l) minutes"
+		elif [[ $(echo "$seconds < 86400" | bc -l) == 1 ]]; then
+			echo "$(echo $seconds/3600 | bc -l) hours"
+		elif [[ $(echo "$seconds < 86400*365.2425" | bc -l) == 1 ]]; then
+			echo "$(echo $seconds/86400 | bc -l) days"
+		else
+			echo "$(echo $seconds/86400/365.2425 | bc -l) years"
+		fi
+		;;
+esac
diff --git a/pkgs/profpatsch/utils-hs/default.nix b/pkgs/profpatsch/utils-hs/default.nix
index 423feb03..9ddd50ec 100644
--- a/pkgs/profpatsch/utils-hs/default.nix
+++ b/pkgs/profpatsch/utils-hs/default.nix
@@ -53,11 +53,23 @@ let
             rev = "e7efbb4f0624e86109acd818942c8cd18a7d9d3d";
             sha256 = "0dismb9vl5fxynasc2kv5baqyzp6gpyybmd5p9g1hlcq3p7pfi24";
           };
+          broken = false;
           buildDepends = old.buildDepends or [] ++ (with hself; [
             dependent-sum prettyprinter (hlib.doJailbreak ref-tf)
           ]);
         });
-      } );# // (import /home/philip/kot/dhall/overlay.nix { inherit haskell fetchFromGitHub; } hself hsuper));
+
+        dhall-nix = hlib.justStaticExecutables (hlib.overrideCabal hsuper.dhall-nix (old: {
+          src = fetchFromGitHub {
+            owner = "Profpatsch";
+            repo = "dhall-nix";
+            # manual update to dhall @0.19
+            rev = "feae0ce5b2ecf4daeeae15c39f427f126c33da7c";
+            sha256 = "1kdsbnj681lf65dsdclcrzj4cab1hh0v22n2140386zvwmawyp6r";
+          };
+          broken = false;
+        }));
+      });
     };
 
   haskellDrv = { name, subfolder, deps }: hps.mkDerivation {
diff --git a/pkgs/profpatsch/xmonad/DhallTypedInput.hs b/pkgs/profpatsch/xmonad/DhallTypedInput.hs
new file mode 100644
index 00000000..18c32b22
--- /dev/null
+++ b/pkgs/profpatsch/xmonad/DhallTypedInput.hs
@@ -0,0 +1,232 @@
+{-# language RecordWildCards, NamedFieldPuns, OverloadedStrings, ScopedTypeVariables, KindSignatures, DataKinds, ScopedTypeVariables, RankNTypes, GADTs, TypeApplications, AllowAmbiguousTypes, LambdaCase #-}
+{- Exports the `inputWithTypeArgs` function, which is able to read dhall files of the normalized form
+
+@
+\(CustomType: Type) ->
+\(AnotherType: Type) ->
+…
+@
+
+and set their actual representation on the Haskell side:
+
+This has various advantages:
+
+- dhall files still type check & normalize with the normal dhall
+  tooling, they are standalone (and the types can be instantiated from
+  dhall as well without any workarounds)
+- It can be used like the default `input` function, no injection of
+  custom symbols in the Normalizer is reqired
+- Brings this style of dhall integration to Haskell, where it was only
+  feasible in nix before, because that is untyped
+
+The dhall types can be instantiated by every Haskell type that has an
+`Interpret` instance. The “name” of the type lambda variable is
+compared on the Haskell side with a type-level string that the user
+provides, to prevent mixups.
+
+TODO:
+- Improve error messages (!)
+- Provide a way to re-use the type mapping on the Haskell side, so
+  that the returned values are not just the normal `Interpret` types,
+  but the mapped ones (with name phantom type)
+-}
+module DhallTypedInput
+( inputWithTypeArgs, TypeArg(..), TypeArgError(..), TypeArgEx(..),  typeArg
+)
+where
+
+import Control.Monad.Trans.State.Strict as State
+import Data.List (foldl')
+import Control.Exception (Exception)
+import qualified Control.Exception
+import qualified Data.Text as Text
+
+import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)
+import Data.Proxy (Proxy(Proxy))
+
+import Dhall (Type(..), InvalidType(..), InputSettings(..), EvaluateSettings(..), rootDirectory, startingContext, normalizer, standardVersion, sourceName, defaultEvaluateSettings, Interpret(..), auto)
+import Dhall.TypeCheck (X)
+import Dhall.Core
+import Dhall.Parser (Src(..))
+import qualified Dhall.Import
+import qualified Dhall.Pretty
+import qualified Dhall.TypeCheck
+import qualified Dhall.Parser
+
+import Lens.Family (LensLike', set, view)
+
+import Data.Text.Prettyprint.Doc (Pretty)
+import qualified Data.Text.Prettyprint.Doc               as Pretty
+import qualified Data.Text.Prettyprint.Doc.Render.Text   as Pretty
+import qualified Data.Text.Prettyprint.Doc.Render.String as Pretty
+
+
+-- | Information about a type argument in the dhall input
+--
+-- If the dhall file starts with @\(CustomType : Type) ->@,
+-- that translates to @TypeArg "CustomType" interpretionType@
+-- where @"CustomType"@ is a type-level string describing the
+-- name of the type in the dhall file (as a sanity check) and
+-- @interpretationType@ is any type which implements
+-- 'Dhall.Interpret'.
+--
+-- This is basically a specialized 'Data.Proxy'.
+data TypeArg (sym :: Symbol) t = TypeArg
+
+-- | Existential wrapper of a 'TypeArg', allows to create a list
+-- of heterogenous 'TypeArg's.
+data TypeArgEx
+  where TypeArgEx :: (KnownSymbol sym, Interpret t) => TypeArg sym t -> TypeArgEx
+
+-- | Shortcut for creating a 'TypeArgEx'.
+--
+-- Use with @TypeApplications@:
+--
+-- @
+-- typeArg @"CustomType" @Integer
+-- @
+typeArg :: forall sym t. (KnownSymbol sym, Interpret t) => TypeArgEx
+typeArg = TypeArgEx (TypeArg :: TypeArg sym t)
+
+-- | Possible errors returned when applying a 'TypeArg'
+-- to a 'Dhall.Expr'.
+data TypeArgError
+  = WrongLabel Text.Text
+  -- ^ The name (label) of the type was different,
+  -- the text value is the expected label.
+  | NoLambda
+  -- ^ The 'Dhall.Expr' does not start with 'Dhall.Lam'.
+
+-- | Apply a 'TypeArg' to a 'Dhall.Expr'.
+--
+-- Checks that the dhall file starts with the 'Dhall.Lam'
+-- corresponding to 'TypeArg`, then applies @t@ (dhall type application)
+-- and normalizes, effectively stripping the 'Dhall.Lam'.
+applyTypeArg
+  :: forall sym t. (KnownSymbol sym, Interpret t)
+  => Expr Src X
+  -> TypeArg sym t
+  -> Either TypeArgError (Expr Src X)
+applyTypeArg expr ta@(TypeArg) = case expr of
+  (Lam label (Const Dhall.Core.Type) _)
+    -> let expectedLabel = getLabel ta
+        in if label /= getLabel ta
+           then Left (WrongLabel expectedLabel)
+           else let expr' = (normalize (App expr tExpect))
+                  in Right expr'
+    where
+        Dhall.Type _ tExpect = Dhall.auto :: Dhall.Type t
+  expr -> Left NoLambda
+
+-- | Inflect the type-level string @sym@ to a text value.
+getLabel :: forall sym t. (KnownSymbol sym) => TypeArg sym t -> Text.Text
+getLabel _ = Text.pack $ symbolVal (Proxy :: (Proxy :: Symbol -> *) sym)
+
+instance (KnownSymbol sym) => Show (TypeArg sym t) where
+  show TypeArg =
+    "TypeArg "
+    ++ (symbolVal (Proxy :: (Proxy :: Symbol -> *) sym))
+
+-- | Takes a list of 'TypeArg's and parses the given
+-- dhall string, applying the given 'TypeArg's in order
+-- to the opaque dhall type arguments (see 'TypeArg' for
+-- how these should look).
+--
+-- This is a slightly changed 'Dhall.inputWith'.
+--
+-- Discussion: Any trace of our custom type is removed from
+-- the resulting
+inputWithTypeArgs
+  :: InputSettings
+  -> [TypeArgEx]
+  -> Dhall.Type a
+  -> Text.Text
+  -> IO a
+inputWithTypeArgs settings typeArgs (Dhall.Type {extract, expected}) txt = do
+    expr <- throws (Dhall.Parser.exprFromText (view sourceName settings) txt)
+
+    -- TODO: evaluateSettings not exposed
+    -- let evSettings = view evaluateSettings settings
+    let evSettings :: EvaluateSettings = defaultEvaluateSettings
+
+    -- -vvv copied verbatim from 'Dhall.inputWith' vvv-
+    let transform =
+               set Dhall.Import.standardVersion
+               (view standardVersion evSettings)
+            .  set Dhall.Import.normalizer
+               (view normalizer evSettings)
+            .  set Dhall.Import.startingContext
+               (view startingContext evSettings)
+
+    let status = transform (Dhall.Import.emptyStatus
+                            (view rootDirectory settings))
+
+    expr' <- State.evalStateT (Dhall.Import.loadWith expr) status
+    -- -^^^ copied verbatim ^^^-
+
+    let
+      -- | if there’s a note, run the transformation and rewrap with the note
+      skipNote e f = case e of
+          Note n e -> Note n $ f e
+          e -> f e
+
+    let
+      -- | strip one 'TypeArg'
+      stripTypeArg :: Expr Src X -> TypeArgEx -> Expr Src X
+      stripTypeArg e (TypeArgEx ta) = skipNote e $ \e' -> case e' of
+          (Lam label _ _) ->
+            case applyTypeArg e' ta of
+              Right e'' -> e''
+              -- TODO obvously improve error messages
+              Left (WrongLabel l) ->
+                error $ "Wrong label, should have been `" ++ Text.unpack l ++ "` but was `" ++ Text.unpack label ++ "`"
+              Left NoLambda -> error $ "I expected a lambda of the form λ(" ++ Text.unpack label ++ ": Type) → but got: " ++ show e
+          e' -> error $ show e'
+
+    -- strip all 'TypeArg's
+    let expr'' = foldl' stripTypeArg expr' typeArgs
+
+    -- -vvv copied verbatim as well (expr' -> expr'') vvv-
+    let suffix = prettyToStrictText expected
+    let annot = case expr'' of
+            Note (Src begin end bytes) _ ->
+                Note (Src begin end bytes') (Annot expr'' expected)
+              where
+                bytes' = bytes <> " : " <> suffix
+            _ ->
+                Annot expr'' expected
+
+    _ <- throws (Dhall.TypeCheck.typeWith (view startingContext settings) annot)
+    case extract (Dhall.Core.normalizeWith (Dhall.Core.getReifiedNormalizer (view normalizer settings)) expr'') of
+        Just x  -> return x
+        Nothing -> Control.Exception.throwIO InvalidType
+
+
+-- copied from Dhall.Pretty.Internal
+prettyToStrictText :: Pretty a => a -> Text.Text
+prettyToStrictText = docToStrictText . Pretty.pretty
+
+-- copied from Dhall.Pretty.Internal
+docToStrictText :: Pretty.Doc ann -> Text.Text
+docToStrictText = Pretty.renderStrict . Pretty.layoutPretty options
+  where
+   options = Pretty.LayoutOptions { Pretty.layoutPageWidth = Pretty.Unbounded }
+
+-- copied from somewhere in Dhall
+throws :: Exception e => Either e a -> IO a
+throws (Left  e) = Control.Exception.throwIO e
+throws (Right r) = return r
+
+
+-- TODO: add errors like these
+-- data WrongTypeLabel = WrongTypeLabel deriving (Typeable)
+
+-- _ERROR :: String
+-- _ERROR = "\ESC[1;31mError\ESC[0m"
+
+-- instance Show WrongTypeLabel where
+--     show WrongTypeLabel =
+--         _ERROR <> ": Mislabelled type lambda
+--         \                                                                                \n\
+--         \Expected your t provide an extract function that succeeds if an expression      \n\
+--         \matches the expected type.  You provided a Type that disobeys this contract     \n"