about summary refs log tree commit diff
path: root/pkgs/development/tools/haskell
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2023-10-18 19:12:22 +0200
committerProfpatsch <mail@profpatsch.de>2023-11-09 17:27:20 +0100
commit8e803f2fb90f96943f69c145e312ad15f07f9b16 (patch)
tree01b14e5bf306f4880987ce61aace51a792dcda27 /pkgs/development/tools/haskell
parent529cbf1a032b58c99e560d976722c03b3e51ae56 (diff)
haskell-language-server: keep only formatters the user wants
This introduces a list of `supportedFormatters` that are the ones that
should be compiled into hls. Removes a nontrivial amount of transitive
dependencies if only one formatter is used in a project.
Diffstat (limited to 'pkgs/development/tools/haskell')
-rw-r--r--pkgs/development/tools/haskell/haskell-language-server/withWrapper.nix79
1 files changed, 76 insertions, 3 deletions
diff --git a/pkgs/development/tools/haskell/haskell-language-server/withWrapper.nix b/pkgs/development/tools/haskell/haskell-language-server/withWrapper.nix
index bcfde333e9bcd..d9f74b4933506 100644
--- a/pkgs/development/tools/haskell/haskell-language-server/withWrapper.nix
+++ b/pkgs/development/tools/haskell/haskell-language-server/withWrapper.nix
@@ -13,8 +13,13 @@
 # Whether to build hls with the dynamic run-time system.
 # See https://haskell-language-server.readthedocs.io/en/latest/troubleshooting.html#static-binaries for more information.
 , dynamic ? true
+
+# which formatters are supported. An empty list means “all”.
+, supportedFormatters ? [ ]
 }:
 
+# make sure the user only sets GHC versions that actually exist
+assert supportedGhcVersions != [];
 assert
   lib.asserts.assertEachOneOf
     "supportedGhcVersions"
@@ -24,6 +29,47 @@ assert
       (lib.filter (lib.hasPrefix "ghc"))
       (map (lib.removePrefix "ghc"))
     ]);
+
+let
+  # A mapping from formatter name to
+  # - cabal flag to disable
+  # - formatter-specific packages that can be stripped from the build of hls if it is disabled
+  knownFormatters = {
+    ormolu = {
+      cabalFlag = "ormolu";
+      packages = [
+        "hls-ormolu-plugin"
+      ];
+    };
+    fourmolu = {
+      cabalFlag = "fourmolu";
+      packages = [
+        "hls-fourmolu-plugin"
+      ];
+    };
+    floskell = {
+      cabalFlag = "floskell";
+      packages = [
+        "hls-floskell-plugin"
+      ];
+    };
+    stylish-haskell = {
+      cabalFlag = "stylishhaskell";
+      packages = [
+        "hls-stylish-haskell-plugin"
+      ];
+    };
+  };
+
+in
+
+# make sure any formatter that is set is actually supported by us
+assert
+  lib.asserts.assertEachOneOf
+    "supportedFormatters"
+    supportedFormatters
+    (lib.attrNames knownFormatters);
+
 #
 # The recommended way to override this package is
 #
@@ -41,6 +87,34 @@ let
 
   getPackages = version: haskell.packages."ghc${version}";
 
+  # Given the list of `supportedFormatters`, remove every formatter that we know of (knownFormatters)
+  # by disabling the cabal flag and also removing the formatter libraries.
+  removeUnnecessaryFormatters =
+    let
+      # only formatters that were not requested
+      unwanted = lib.pipe knownFormatters [
+        (lib.filterAttrs (fmt: _: ! (lib.elem fmt supportedFormatters)))
+        lib.attrsToList
+      ];
+      # all flags to disable
+      flags = map (fmt: fmt.value.cabalFlag) unwanted;
+      # all dependencies to remove from hls
+      deps = lib.concatMap (fmt: fmt.value.packages) unwanted;
+
+      # remove nulls from a list
+      stripNulls = lib.filter (x: x != null);
+
+      # remove all unwanted dependencies of formatters we don’t want
+      stripDeps = overrideCabal (drv: {
+        libraryHaskellDepends = lib.pipe (drv.libraryHaskellDepends or []) [
+          # the existing list may contain nulls, so let’s strip them first
+          stripNulls
+          (lib.filter (dep: ! (lib.elem dep.pname deps)))
+        ];
+      });
+
+    in drv: lib.pipe drv ([stripDeps] ++ map disableCabalFlag flags);
+
   tunedHls = hsPkgs:
     lib.pipe hsPkgs.haskell-language-server ([
       (haskell.lib.compose.overrideCabal (old: {
@@ -52,6 +126,7 @@ let
         '';
       }))
       ((if dynamic then enableCabalFlag else disableCabalFlag) "dynamic")
+      (if supportedFormatters != [] then removeUnnecessaryFormatters else lib.id)
     ]
     ++ lib.optionals (!dynamic) [
       justStaticExecutables
@@ -69,9 +144,7 @@ let
         }/bin/haskell-language-server $out/bin/${x}")
       (targets version);
 
-in
-assert supportedGhcVersions != []; stdenv.mkDerivation
-{
+in stdenv.mkDerivation {
   pname = "haskell-language-server";
   version = haskellPackages.haskell-language-server.version;