Skip to content

Commit f253979

Browse files
authored
Gnls (#93)
* Initial work * More * Update hashes and fix paths * Progress on go GNLS tests * gnls: tests passing with 20 repeats
1 parent 60492c3 commit f253979

14 files changed

Lines changed: 328 additions & 46 deletions

File tree

modules/kernels/go/default.nix

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{ callPackage
22
, gopls
33
, lib
4-
, pkgs
54
, symlinkJoin
5+
, system
66

77
, go
88

@@ -22,7 +22,10 @@ let
2222

2323
languageServers =
2424
[]
25-
++ lib.optionals settings.lsp.gopls.enable [(callPackage ./language-server-gopls.nix { inherit go attrs; inherit kernelName; })]
25+
++ lib.optionals settings.lsp.gopls.enable [(callPackage ./language-server-gopls/language-server-gopls.nix {
26+
inherit go attrs kernelName system;
27+
settings = settings.lsp.gopls;
28+
})]
2629
;
2730

2831
packageOptions = {};
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#! /usr/bin/env nix-shell
2+
#! nix-shell -i bash -p nix-prefetch python3
3+
4+
VERSION=$(nix eval --raw --expr 'import ./gnls-version.nix' --impure)
5+
6+
echo "Got version: $VERSION"
7+
8+
NAME="go-notebook-language-server-$VERSION"
9+
10+
NEW_HASHES=$(
11+
for system in aarch64-linux x86_64-linux x86_64-darwin aarch64-darwin; do
12+
URL="https://github.com/codedownio/go-notebook-language-server/releases/download/v${VERSION}/go-notebook-language-server-${VERSION}-${system}.tar.gz"
13+
HASH=$(nix-prefetch fetchzip --name "$NAME" --no-stripRoot --url "$URL" 2>/dev/null)
14+
15+
echo >&2 "$URL -> $HASH"
16+
17+
echo " \"$system\" = fetchzip {"
18+
echo " name = \"$NAME\";"
19+
echo " stripRoot = false;"
20+
echo " url = \"$URL\";"
21+
echo " hash = \"$HASH\";"
22+
echo " };"
23+
done
24+
)
25+
26+
py_script=$(cat <<END
27+
from operator import indexOf
28+
import sys
29+
30+
input = sys.stdin.read()
31+
32+
with open("./gnls.nix", 'r') as f:
33+
lines = f.readlines()
34+
35+
start_index = indexOf(map(lambda x: "HASHES_START" in x, lines), True)
36+
end_index = indexOf(map(lambda x: "HASHES_END" in x, lines), True)
37+
38+
with open("./gnls.nix", 'w') as f:
39+
f.write("".join(lines[0:(start_index+1)]) + input + "".join(lines[end_index:]))
40+
41+
END
42+
)
43+
44+
echo "$NEW_HASHES" | python -c "$py_script"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"0.1.0.2"
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{ fetchzip
2+
, system
3+
}:
4+
5+
# Fetch a static binary from GitHub releases
6+
{
7+
# HASHES_START
8+
"aarch64-linux" = fetchzip {
9+
name = "go-notebook-language-server-0.1.0.2";
10+
stripRoot = false;
11+
url = "https://github.com/codedownio/go-notebook-language-server/releases/download/v0.1.0.2/go-notebook-language-server-0.1.0.2-aarch64-linux.tar.gz";
12+
hash = "sha256-I1qxFLjlc1E/zaC2+tcH0STlnkr1nulBb3UWm83iHcE=";
13+
};
14+
"x86_64-linux" = fetchzip {
15+
name = "go-notebook-language-server-0.1.0.2";
16+
stripRoot = false;
17+
url = "https://github.com/codedownio/go-notebook-language-server/releases/download/v0.1.0.2/go-notebook-language-server-0.1.0.2-x86_64-linux.tar.gz";
18+
hash = "sha256-uzkTEPXQXlqusKyLDDgOd0huCer7fGyFN2FI7qHMiZg=";
19+
};
20+
"x86_64-darwin" = fetchzip {
21+
name = "go-notebook-language-server-0.1.0.2";
22+
stripRoot = false;
23+
url = "https://github.com/codedownio/go-notebook-language-server/releases/download/v0.1.0.2/go-notebook-language-server-0.1.0.2-x86_64-darwin.tar.gz";
24+
hash = "sha256-O/d0lnwL5zEQ6tLROv01k/r9OwpdJAvL3lIZk+T2/Ng=";
25+
};
26+
"aarch64-darwin" = fetchzip {
27+
name = "go-notebook-language-server-0.1.0.2";
28+
stripRoot = false;
29+
url = "https://github.com/codedownio/go-notebook-language-server/releases/download/v0.1.0.2/go-notebook-language-server-0.1.0.2-aarch64-darwin.tar.gz";
30+
hash = "sha256-HyO/oU0BNWXu2evIGHm9XlUBVI43+PerlZ9eqXp0B7M=";
31+
};
32+
# HASHES_END
33+
}.${system}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{ buildGoModule
2+
, fetchFromGitHub
3+
, lib
4+
}:
5+
6+
buildGoModule rec {
7+
pname = "go-parser";
8+
version = import ./gnls-version.nix;
9+
10+
src = fetchFromGitHub {
11+
owner = "codedownio";
12+
repo = "go-notebook-language-server";
13+
rev = "v${version}";
14+
hash = "sha256-SdN/v4psQRQ8O+3BosYgcZzBZSxNytVmw1A/lM2fQ/4=";
15+
};
16+
17+
sourceRoot = "${src.name}/go-parser";
18+
19+
vendorHash = null;
20+
21+
meta = with lib; {
22+
description = "Go notebook code parser using go/scanner";
23+
homepage = "https://github.com/codedownio/go-notebook-language-server";
24+
license = licenses.bsd3;
25+
platforms = platforms.unix;
26+
mainProgram = "go-parser";
27+
};
28+
}

modules/kernels/go/language-server-gopls.nix renamed to modules/kernels/go/language-server-gopls/language-server-gopls.nix

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,32 @@
33
, runCommand
44
, makeWrapper
55
, pkgs
6+
, system
67

78
, attrs
89
, kernelName
10+
, settings
911

1012
, go
1113
, gopls
12-
# , go-langserver
1314
}:
1415

1516
let
16-
common = callPackage ../common.nix {};
17+
common = callPackage ../../common.nix {};
18+
19+
gnlsVersion = import ./gnls-version.nix;
20+
21+
gnls = callPackage ./gnls.nix { inherit system; };
22+
23+
go-parser = callPackage ./go-parser.nix {};
24+
25+
gnls-wrapped = runCommand "go-notebook-language-server-${gnlsVersion}-wrapped" {
26+
nativeBuildInputs = [ makeWrapper ];
27+
} ''
28+
mkdir -p $out/bin
29+
makeWrapper ${gnls}/bin/go-notebook-language-server $out/bin/go-notebook-language-server \
30+
--prefix PATH : ${go-parser}/bin
31+
'';
1732

1833
goplsWrapped = runCommand "gopls-wrapped" { buildInputs = [makeWrapper]; } ''
1934
mkdir -p $out/bin
@@ -36,32 +51,20 @@ common.writeTextDirWithMetaAndPassthru gopls.meta passthru "lib/codedown/languag
3651
version = gopls.version;
3752
display_name = "gopls";
3853
description = gopls.meta.description;
39-
icon = ./go-logo-64x64.png;
54+
icon = ../go-logo-64x64.png;
4055
extensions = ["go"];
4156
notebook_suffix = ".go";
4257
kernel_name = kernelName;
4358
header_lines = ["package Notebook"];
4459
attrs = attrs;
4560
type = "stream";
46-
args = ["${goplsWrapped}/bin/gopls"];
61+
args = [
62+
"${gnls-wrapped}/bin/go-notebook-language-server"
63+
"--wrapped-server" "${goplsWrapped}/bin/gopls"
64+
]
65+
++ lib.optionals settings.debug ["--log-level" "debug"]
66+
++ lib.optionals settings.super-debug ["--debug-client-writes" "--debug-client-reads" "--debug-server-writes" "--debug-server-reads"]
67+
;
4768
env = {};
4869
language_id = "go";
4970
}])
50-
51-
52-
# Deprecated: go-langserver
53-
# https://github.com/sourcegraph/go-langserver
54-
# common.writeTextDirWithMeta go-langserver.meta "lib/codedown/language-servers/go-langserver.yaml" (lib.generators.toYAML {} [{
55-
# name = "go-langserver";
56-
# display_name = "go-langserver";
57-
# description = go-langserver.meta.description;
58-
# icon = ./go-logo-64x64.png;
59-
# extensions = ["go"];
60-
# notebook_suffix = ".go";
61-
# kernel_name = kernelName;
62-
# header_lines = ["package Notebook"];
63-
# attrs = ["go"];
64-
# type = "stream";
65-
# args = ["${go-langserver}/bin/go-langserver"];
66-
# env = {};
67-
# }])

modules/kernels/go/module.nix

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ with lib;
4747
type = types.bool;
4848
default = true;
4949
};
50+
lsp.gopls.debug = mkOption {
51+
example = "Gopls: enable debug output";
52+
type = types.bool;
53+
default = false;
54+
};
55+
lsp.gopls.super-debug = mkOption {
56+
example = "Gopls: enable verbose debug output";
57+
type = types.bool;
58+
default = false;
59+
};
5060

5161
go.gocache = mkOption {
5262
example = "Value of GOCACHE environment variable";

tests/app/Spec/Tests/Go.hs

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,45 @@ import TestLib.NixTypes
1313
import TestLib.TestSearchers
1414
import TestLib.Types
1515

16+
import qualified Spec.Tests.Go.Completion as Completion
17+
import qualified Spec.Tests.Go.Hovers as Hovers
1618

17-
kernelSpec :: NixKernelSpec
18-
kernelSpec = NixKernelSpec {
19+
20+
tests :: LanguageSpec
21+
tests = describe "Go" $ do
22+
testKernelSearchersBuild "go"
23+
testHasExpectedFields "go"
24+
25+
introduceNixEnvironment [kernelSpecWithLsp] [] "Go" $ introduceJupyterRunner $ do
26+
describe "Kernel tests" $ do
27+
testKernelStdout "go" [__i|import("fmt")
28+
fmt.Println("hi")|] "hi\n"
29+
30+
describe "LSP" $ do
31+
testDiagnosticsLabel "gopls: Undeclared name" lsName "test.go" LanguageKind_Go printUnknownCode $ \diagnostics ->
32+
assertDiagnosticRanges diagnostics [(Range (Position 3 12) (Position 3 15), Just (InR "UndeclaredName"))]
33+
34+
Completion.tests
35+
36+
Hovers.tests
37+
38+
lsName :: Text
39+
lsName = "gopls"
40+
41+
kernelSpecWithLsp :: NixKernelSpec
42+
kernelSpecWithLsp = NixKernelSpec {
1943
nixKernelName = "go"
2044
, nixKernelChannel = "codedown"
2145
, nixKernelDisplayName = Just "Go"
2246
, nixKernelPackages = []
2347
, nixKernelMeta = Nothing
2448
, nixKernelIcon = Nothing
25-
, nixKernelExtraConfig = Nothing
49+
, nixKernelExtraConfig = Just [
50+
"lsp.gopls.enable = true"
51+
, "lsp.gopls.debug = true"
52+
]
2653
}
2754

28-
tests :: LanguageSpec
29-
tests = describe "Go" $ introduceNixEnvironment [kernelSpec] [] "Go" $ introduceJupyterRunner $ do
30-
testKernelSearchersBuild "go"
31-
testHasExpectedFields "go"
32-
33-
testKernelStdout "go" [__i|import("fmt")
34-
fmt.Println("hi")|] "hi\n"
35-
36-
testDiagnosticsLabel "gopls: Undeclared name" "gopls" "test.go" LanguageKind_Go printUnknownCode $ \diagnostics ->
37-
assertDiagnosticRanges diagnostics [(Range (Position 3 12) (Position 3 15), Just (InR "UndeclaredName"))]
38-
3955
printUnknownCode :: Text
4056
printUnknownCode = [__i|package main
4157
import ("fmt")

tests/app/Spec/Tests/Go/Common.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module Spec.Tests.Go.Common where
2+
3+
import Data.Text
4+
5+
6+
lsName :: Text
7+
lsName = "gopls"
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
module Spec.Tests.Go.Completion (tests) where
2+
3+
import Control.Lens
4+
import Control.Monad.IO.Unlift
5+
import qualified Data.List as L
6+
import Data.String.Interpolate
7+
import Data.Text (Text)
8+
import Language.LSP.Protocol.Lens
9+
import Language.LSP.Protocol.Types
10+
import Language.LSP.Test
11+
import qualified Language.LSP.Test.Helpers as Helpers
12+
import Spec.Tests.Go.Common
13+
import Test.Sandwich as Sandwich
14+
import Test.Sandwich.Waits (waitUntil)
15+
import TestLib.LSP
16+
import TestLib.Types
17+
18+
19+
tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m ()
20+
tests = describe "Completions" $ do
21+
describe "main.ipynb" $ do
22+
it "provides fmt. completions" $ doSession' "main.ipynb" lsName fmtCompletionCodeNotebook $ \(Helpers.LspSessionInfo {..}) -> do
23+
ident <- openDoc lspSessionInfoFileName LanguageKind_Go
24+
25+
waitUntil 60 $ do
26+
completions <- getCompletions ident (Position 1 4)
27+
info [i|Got completions: #{completions}|]
28+
let insertTexts = fmap (^. label) completions
29+
insertTexts `listShouldContain` "Println"
30+
insertTexts `listShouldContain` "Printf"
31+
32+
it "provides local variable completions" $ doSession' "main.ipynb" lsName localVarCodeNotebook $ \(Helpers.LspSessionInfo {..}) -> do
33+
ident <- openDoc lspSessionInfoFileName LanguageKind_Go
34+
35+
waitUntil 60 $ do
36+
completions <- getCompletions ident (Position 2 2)
37+
info [i|Got completions: #{completions}|]
38+
let insertTexts = fmap (^. label) completions
39+
insertTexts `listShouldContain` "myVariable"
40+
insertTexts `listShouldContain` "myFloat"
41+
42+
describe "test.go" $ do
43+
it "provides fmt. completions" $ doSession' "test.go" lsName fmtCompletionCodeStandalone $ \(Helpers.LspSessionInfo {..}) -> do
44+
ident <- openDoc lspSessionInfoFileName LanguageKind_Go
45+
46+
waitUntil 60 $ do
47+
completions <- getCompletions ident (Position 3 8)
48+
info [i|Got completions: #{completions}|]
49+
let insertTexts = fmap (^. label) completions
50+
insertTexts `listShouldContain` "Println"
51+
insertTexts `listShouldContain` "Printf"
52+
53+
it "provides local variable completions" $ doSession' "test.go" lsName localVarCodeStandalone $ \(Helpers.LspSessionInfo {..}) -> do
54+
ident <- openDoc lspSessionInfoFileName LanguageKind_Go
55+
56+
waitUntil 60 $ do
57+
completions <- getCompletions ident (Position 4 6)
58+
info [i|Got completions: #{completions}|]
59+
let insertTexts = fmap (^. label) completions
60+
insertTexts `listShouldContain` "myVariable"
61+
insertTexts `listShouldContain` "myFloat"
62+
63+
fmtCompletionCodeNotebook :: Text
64+
fmtCompletionCodeNotebook = [__i|import "fmt"
65+
fmt.|]
66+
67+
localVarCodeNotebook :: Text
68+
localVarCodeNotebook = [__i|myVariable := 42
69+
myFloat := 3.14
70+
my|]
71+
72+
fmtCompletionCodeStandalone :: Text
73+
fmtCompletionCodeStandalone = [__i|package main
74+
import "fmt"
75+
func main() {
76+
fmt.
77+
}|]
78+
79+
localVarCodeStandalone :: Text
80+
localVarCodeStandalone = [__i|package main
81+
func main() {
82+
myVariable := 42
83+
myFloat := 3.14
84+
my
85+
}|]
86+
87+
listShouldContain :: (MonadIO m, Eq a, Show a) => [a] -> a -> m ()
88+
listShouldContain haystack needle = case L.elem needle haystack of
89+
True -> return ()
90+
False -> expectationFailure [i|Expected list to contain #{show needle}, but had: #{show haystack}|]

0 commit comments

Comments
 (0)