Merge pull request #261848 from Profpatsch/haskell-language-server-disable-formatters

haskell-language-server: allow specifying a set of formatters that should be included
This commit is contained in:
maralorn 2023-11-09 19:21:09 +01:00 committed by GitHub
commit b9534d6574
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 152 additions and 15 deletions

View File

@ -50,4 +50,33 @@ rec {
lib.generators.toPretty {} xs}, but is: ${
lib.generators.toPretty {} val}";
/* Specialized `assertMsg` for checking if every one of `vals` is one of the elements
of the list `xs`. Useful for checking lists of supported attributes.
Example:
let sslLibraries = [ "libressl" "bearssl" ];
in assertEachOneOf "sslLibraries" sslLibraries [ "openssl" "bearssl" ]
stderr> error: each element in sslLibraries must be one of [
stderr> "openssl"
stderr> "bearssl"
stderr> ], but is: [
stderr> "libressl"
stderr> "bearssl"
stderr> ]
Type:
assertEachOneOf :: String -> List ComparableVal -> List ComparableVal -> Bool
*/
assertEachOneOf =
# The name of the variable the user entered `val` into, for inclusion in the error message
name:
# The list of values of what the user provided, to be compared against the values in `xs`
vals:
# The list of valid values
xs:
assertMsg
(lib.all (val: lib.elem val xs) vals)
"each element in ${name} must be one of ${
lib.generators.toPretty {} xs}, but is: ${
lib.generators.toPretty {} vals}";
}

View File

@ -1,10 +1,77 @@
{ lib
, stdenv
, supportedGhcVersions ? [ "94" ]
, dynamic ? true
, haskellPackages
, haskell
# Which GHC versions this hls can support.
# These are looked up in nixpkgs as `pkgs.haskell.packages."ghc${version}`.
# Run
# $ nix-instantiate --eval -E 'with import <nixpkgs> {}; builtins.attrNames pkgs.haskell.packages'
# to list for your nixpkgs version.
, supportedGhcVersions ? [ "94" ]
# 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. Pass `[]` to remove all formatters.
#
# Maintainers: if a new formatter is added, add it here and down in knownFormatters
, supportedFormatters ? [ "ormolu" "fourmolu" "floskell" "stylish-haskell" ]
}:
# make sure the user only sets GHC versions that actually exist
assert supportedGhcVersions != [];
assert
lib.asserts.assertEachOneOf
"supportedGhcVersions"
supportedGhcVersions
(lib.pipe haskell.packages [
lib.attrNames
(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
#
@ -13,9 +80,43 @@
# for example. Read more about this in the haskell-language-server section of the nixpkgs manual.
#
let
inherit (lib) concatStringsSep concatMapStringsSep take splitString pipe optionals;
inherit (haskell.lib.compose) justStaticExecutables overrideCabal enableCabalFlag disableCabalFlag;
inherit (haskell.lib.compose)
justStaticExecutables
overrideCabal
enableCabalFlag
disableCabalFlag
;
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 dont want
stripDeps = overrideCabal (drv: {
libraryHaskellDepends = lib.pipe (drv.libraryHaskellDepends or []) [
# the existing list may contain nulls, so lets 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: {
@ -27,32 +128,39 @@ let
'';
}))
((if dynamic then enableCabalFlag else disableCabalFlag) "dynamic")
] ++ optionals (!dynamic) [
removeUnnecessaryFormatters
]
++ lib.optionals (!dynamic) [
justStaticExecutables
]);
targets = version:
let packages = getPackages version;
in [
"haskell-language-server-${packages.ghc.version}"
];
in [ "haskell-language-server-${packages.ghc.version}" ];
makeSymlinks = version:
concatMapStringsSep "\n" (x:
"ln -s ${
tunedHls (getPackages version)
}/bin/haskell-language-server $out/bin/${x}") (targets version);
in assert supportedGhcVersions != []; stdenv.mkDerivation {
lib.concatMapStringsSep "\n"
(x:
"ln -s ${
tunedHls (getPackages version)
}/bin/haskell-language-server $out/bin/${x}")
(targets version);
in stdenv.mkDerivation {
pname = "haskell-language-server";
version = haskellPackages.haskell-language-server.version;
buildCommand = ''
mkdir -p $out/bin
ln -s ${tunedHls (getPackages (builtins.head supportedGhcVersions))}/bin/haskell-language-server-wrapper $out/bin/haskell-language-server-wrapper
${concatMapStringsSep "\n" makeSymlinks supportedGhcVersions}
${lib.concatMapStringsSep "\n" makeSymlinks supportedGhcVersions}
'';
meta = haskellPackages.haskell-language-server.meta // {
maintainers = [ lib.maintainers.maralorn ];
longDescription = ''
This package provides the executables ${
concatMapStringsSep ", " (x: concatStringsSep ", " (targets x))
lib.concatMapStringsSep ", " (x: lib.concatStringsSep ", " (targets x))
supportedGhcVersions
} and haskell-language-server-wrapper.
You can choose for which ghc versions to install hls with pkgs.haskell-language-server.override { supportedGhcVersions = [ "90" "92" ]; }.