Skip to content

Commit 067b7c3

Browse files
committed
feat: add jupyterlab-lsp support
1 parent 9fc7d31 commit 067b7c3

File tree

4 files changed

+189
-28
lines changed

4 files changed

+189
-28
lines changed

flake.nix

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@
316316

317317
mkJupyterlab = {
318318
jupyterlabEnvArgs ? {},
319+
notebookConfig ? {},
319320
kernels ? k: [], # k: [ (k.python {}) k.bash ],
320321
# extensions ? e: [], # e: [ e.jupy-ext ]
321322
runtimePackages ? [], # runtime package available to all binaries
@@ -390,14 +391,19 @@
390391
jupyterlabEnv = jupyterlabEnvWrapped (baseArgs // jupyterlabEnvArgs);
391392

392393
# create directories for storing jupyter configs
393-
jupyterDir = pkgs.runCommand "jupyter-dir" {} ''
394-
# make jupyter config and data directories
395-
mkdir -p $out/config $out/data
396-
echo "c.NotebookApp.use_redirect_file = False" > $out/config/jupyter_notebook_config.py
397-
398-
# make jupyter lab user settings and workspaces directories
399-
mkdir -p $out/config/lab/{user-settings,workspaces}
400-
'';
394+
jupyterDir = let
395+
mergeNotebookConfig = lib.recursiveUpdate notebookConfig {
396+
NotebookApp.use_redirect_file = false;
397+
KernelSpecManager.whitelist = map (x: x.name) userKernels;
398+
};
399+
in
400+
pkgs.runCommand "jupyter-dir" {} ''
401+
# make jupyter config and data directories
402+
mkdir -p $out/config $out/data
403+
echo '${builtins.toJSON mergeNotebookConfig}' > $out/config/jupyter_notebook_config.json
404+
# make jupyter lab user settings and workspaces directories
405+
mkdir -p $out/config/lab/{user-settings,workspaces}
406+
'';
401407

402408
/*
403409
Finds kernels from kernelDerivations that have the same kernel
@@ -624,7 +630,7 @@
624630
};
625631
}
626632
))
627-
// rec {
633+
// {
628634
jupyterKernels = builtins.mapAttrs mkKernelFlakeOutput kernelsConfig.available;
629635
templates.default = {
630636
path = ./template;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"LanguageServerManager": {
3+
"language_servers": {
4+
"haskell-language-server": {
5+
"version": 2,
6+
"argv": ["haskell-language-server-wrapper", "lsp"],
7+
"languages": ["haskell"],
8+
"display_name": "haskell-language-server",
9+
"mimetypes": ["text/haskell", "text/x-haskell"]
10+
}
11+
}
12+
}
13+
}

modules/default.nix

Lines changed: 128 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,69 @@ in {
1919
description = "A list of runtime packages available to all binaries";
2020
default = [];
2121
};
22+
notebookConfig = lib.mkOption {
23+
type = types.attrs;
24+
description = "jupyter notebook config which will be written to jupyter_notebook_config.py";
25+
default = {};
26+
apply = c: lib.recursiveUpdate (lib.importJSON ./conf/jupyter_notebook_config.json) c;
27+
};
28+
29+
extensions = {
30+
features = lib.mkOption {
31+
type = types.listOf types.str;
32+
description = "A list of features to enable";
33+
default = [];
34+
example = ["lsp"];
35+
};
36+
languageServers = lib.mkOption {
37+
default = {};
38+
description = "Which language servers package to use";
39+
type = types.submodule {
40+
options = {
41+
python = lib.mkOption {
42+
type = types.functionTo types.package;
43+
description = "Python language server";
44+
default = ps: ps.python-lsp-server;
45+
example = lib.literalExpression ''
46+
if you want to use pyls-mypy or othter dependencies, you can do:
47+
extraPackages = ps: [] ++ python-lsp-server.passthru.optional-dependencies.all;
48+
'';
49+
};
50+
haskell = lib.mkOption {
51+
type = types.package;
52+
description = "Haskell language server";
53+
default = config.nixpkgs.haskell-language-server;
54+
example = lib.literalExpression ''
55+
config.nixpkgs.haskell-language-server.override { supportedGhcVersions = [ "90" "94" ]; };
56+
'';
57+
};
58+
};
59+
};
60+
};
61+
};
62+
63+
jupyterlabEnvArgs = lib.mkOption {
64+
type = types.submodule {
65+
options =
66+
{
67+
extraPackages = lib.mkOption {
68+
type = types.functionTo (types.listOf types.package);
69+
default = ps: [];
70+
example = ps: [ps.jupytext];
71+
description = lib.mdDoc "A list of packages for extending the jupyterlab environment";
72+
};
73+
}
74+
// (lib.recursiveUpdate (import ./types/poetry.nix {
75+
inherit lib self;
76+
config = config.jupyterlab.jupyterlabEnvArgs;
77+
})
78+
{
79+
projectDir.default = self.outPath;
80+
});
81+
};
82+
default = {};
83+
description = "Arguments for the jupyterlab poetry's environment";
84+
};
2285
};
2386

2487
# flakes ? [], # flakes where to detect custom kernels/extensions
@@ -53,27 +116,73 @@ in {
53116
#++ map (name: ./. + "/../kernels/available/${name}/module.nix") (builtins.attrNames (builtins.readDir ./../kernels/available));
54117

55118
config = {
56-
build = mkJupyterlab {
57-
#jupyterlabEnvArgs = config.jupyterlabEnvArgs;
58-
kernels = availableKernels:
59-
lib.flatten
60-
(
61-
builtins.map
119+
build = let
120+
findFeature = name:
121+
if config.jupyterlab.extensions.features != []
122+
then
62123
(
63-
kernelTypeName:
64-
builtins.map
65-
(
66-
kernelName:
67-
availableKernels.${kernelTypeName}
68-
config.kernel.${kernelTypeName}.${kernelName}.kernelArgs
69-
)
70-
(builtins.attrNames config.kernel.${kernelTypeName})
124+
if (lib.intersectLists [name] config.jupyterlab.extensions.features) != []
125+
then true
126+
else false
71127
)
72-
(builtins.attrNames config.kernel)
73-
);
74-
runtimePackages = config.jupyterlab.runtimePackages;
75-
#flakes = config.flakes;
76-
};
128+
else false;
129+
130+
enabledLanguage = lang: feature:
131+
(
132+
if config.kernel.${lang} != {}
133+
then true
134+
else false
135+
)
136+
&& (findFeature feature);
137+
in
138+
mkJupyterlab {
139+
jupyterlabEnvArgs = {
140+
inherit
141+
(config.jupyterlab.jupyterlabEnvArgs)
142+
pyproject
143+
projectDir
144+
editablePackageSources
145+
preferWheels
146+
poetrylock
147+
poetry2nix
148+
;
149+
150+
# all of python packages should be kept in extraPackages, instead of runtimePackages
151+
extraPackages = ps:
152+
(lib.optionals (enabledLanguage "python" "lsp") [
153+
(config.jupyterlab.extensions.languageServers.python ps)
154+
])
155+
++ (lib.optionals (findFeature "jupytext") [ps.jupytext])
156+
++ (lib.optionals (findFeature "lsp") [ps.jupyter-lsp])
157+
++ (config.jupyterlab.jupyterlabEnvArgs.extraPackages ps);
158+
};
159+
160+
notebookConfig = config.jupyterlab.notebookConfig;
161+
162+
runtimePackages =
163+
config.jupyterlab.runtimePackages
164+
++ (lib.optionals (enabledLanguage "haskell" "lsp") [
165+
config.jupyterlab.extensions.languageServers.haskell
166+
]);
167+
168+
kernels = availableKernels:
169+
lib.flatten
170+
(
171+
builtins.map
172+
(
173+
kernelTypeName:
174+
builtins.map
175+
(
176+
kernelName:
177+
availableKernels.${kernelTypeName}
178+
config.kernel.${kernelTypeName}.${kernelName}.kernelArgs
179+
)
180+
(builtins.attrNames config.kernel.${kernelTypeName})
181+
)
182+
(builtins.attrNames config.kernel)
183+
);
184+
#flakes = config.flakes;
185+
};
77186
_module.args.pkgs = config.nixpkgs;
78187
};
79188
}

template/lsp.nix

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
pkgs,
3+
config,
4+
...
5+
}: {
6+
jupyterlab = {
7+
extensions = {
8+
features = ["lsp" "jupytext"];
9+
languageServers = {
10+
python = ps: ps.python-lsp-server;
11+
};
12+
};
13+
notebookConfig = {
14+
# add your custom language server config here or other notebook config for the jupyterlab_notebook_config.json
15+
# LanguageServerManager.language_servers.custom-language-servers
16+
# "argv" = ["haskell-language-server" "--lsp"];
17+
# "languages" = ["haskell"];
18+
# "display_name" = "haskell-language-server";
19+
# "mimetypes" = ["text/haskell" "text/x-haskell"];
20+
# };
21+
};
22+
runtimePackages = [];
23+
jupyterlabEnvArgs.extraPackages = ps: ([] ++ ps.python-lsp-server.passthru.optional-dependencies.all);
24+
};
25+
kernel.python.minimal = {
26+
enable = true;
27+
};
28+
# FIXME: haskell-language-server is not yet support in jupyterlab-lsp
29+
kernel.haskell.minimal = {
30+
enable = true;
31+
haskellCompiler = "ghc902";
32+
};
33+
}

0 commit comments

Comments
 (0)