Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion modules/kernels/cpp/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
, clang
, xeus-cling
, llvmPackages
, system

, settings
, settingsSchema
Expand All @@ -23,7 +24,10 @@ let
common = callPackage ../common.nix {};

languageServers = lib.optionals settings.lsp.clangd.enable
[(callPackage ./language_server_clangd { inherit kernelName llvmPackages; })];
[(callPackage ./language_server_clangd {
inherit kernelName llvmPackages system cling;
settings = settings.lsp.clangd;
})];

displaySuffix = {
"c++17" = " 17";
Expand Down
37 changes: 37 additions & 0 deletions modules/kernels/cpp/language_server_clangd/cling-parser.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{ lib
, stdenv
, fetchFromGitHub
, cmake
, cling
, zlib
, ncurses
}:

stdenv.mkDerivation rec {
pname = "cling-parser";
version = import ./cnls-version.nix;

src = fetchFromGitHub {
owner = "codedownio";
repo = "cpp-notebook-language-server";
rev = "v${version}";
hash = "sha256-+Af5Rn03iaV5JcKVr8625YPOjqZx8Pf/4Chv6bqcwJY=";
};

sourceRoot = "${src.name}/cling-parser";

nativeBuildInputs = [ cmake ];

buildInputs = [ cling.unwrapped zlib ncurses ];

cmakeFlags = [
"-DLLVM_CONFIG=${cling.unwrapped}/bin/llvm-config"
];

meta = with lib; {
description = "Minimal Cling parser for cpp-notebook-language-server";
homepage = "https://github.com/codedownio/cpp-notebook-language-server";
license = licenses.bsd3;
platforms = platforms.all;
};
}
44 changes: 44 additions & 0 deletions modules/kernels/cpp/language_server_clangd/cnls-update.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#! /usr/bin/env nix-shell
#! nix-shell -i bash -p nix-prefetch python3

VERSION=$(nix eval --raw --expr 'import ./cnls-version.nix' --impure)

echo "Got version: $VERSION"

NAME="cpp-notebook-language-server-$VERSION"

NEW_HASHES=$(
for system in aarch64-linux x86_64-linux x86_64-darwin aarch64-darwin; do
URL="https://github.com/codedownio/cpp-notebook-language-server/releases/download/v${VERSION}/cpp-notebook-language-server-${VERSION}-${system}.tar.gz"
HASH=$(nix-prefetch fetchzip --name "$NAME" --no-stripRoot --url "$URL" 2>/dev/null)

echo >&2 "$URL -> $HASH"

echo " \"$system\" = fetchzip {"
echo " name = \"$NAME\";"
echo " stripRoot = false;"
echo " url = \"$URL\";"
echo " hash = \"$HASH\";"
echo " };"
done
)

py_script=$(cat <<END
from operator import indexOf
import sys

input = sys.stdin.read()

with open("./cnls.nix", 'r') as f:
lines = f.readlines()

start_index = indexOf(map(lambda x: "HASHES_START" in x, lines), True)
end_index = indexOf(map(lambda x: "HASHES_END" in x, lines), True)

with open("./cnls.nix", 'w') as f:
f.write("".join(lines[0:(start_index+1)]) + input + "".join(lines[end_index:]))

END
)

echo "$NEW_HASHES" | python -c "$py_script"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"0.1.0.2"
33 changes: 33 additions & 0 deletions modules/kernels/cpp/language_server_clangd/cnls.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{ fetchzip
, system
}:

# Fetch a static binary from GitHub releases
{
# HASHES_START
"aarch64-linux" = fetchzip {
name = "cpp-notebook-language-server-0.1.0.2";
stripRoot = false;
url = "https://github.com/codedownio/cpp-notebook-language-server/releases/download/v0.1.0.2/cpp-notebook-language-server-0.1.0.2-aarch64-linux.tar.gz";
hash = "sha256-1/RkOXXxgL6YiJ54T82Vii+MC1tbpXSeVIWFzaTLBbk=";
};
"x86_64-linux" = fetchzip {
name = "cpp-notebook-language-server-0.1.0.2";
stripRoot = false;
url = "https://github.com/codedownio/cpp-notebook-language-server/releases/download/v0.1.0.2/cpp-notebook-language-server-0.1.0.2-x86_64-linux.tar.gz";
hash = "sha256-CwdcEOsM3Mwy6F9B81U4an8gWrq/sdc2N809ni4SWMo=";
};
"x86_64-darwin" = fetchzip {
name = "cpp-notebook-language-server-0.1.0.2";
stripRoot = false;
url = "https://github.com/codedownio/cpp-notebook-language-server/releases/download/v0.1.0.2/cpp-notebook-language-server-0.1.0.2-x86_64-darwin.tar.gz";
hash = "sha256-GyxLufGx4bCoFFhQ19E9GTEBXZCvEbMzYM103IDkjJ8=";
};
"aarch64-darwin" = fetchzip {
name = "cpp-notebook-language-server-0.1.0.2";
stripRoot = false;
url = "https://github.com/codedownio/cpp-notebook-language-server/releases/download/v0.1.0.2/cpp-notebook-language-server-0.1.0.2-aarch64-darwin.tar.gz";
hash = "sha256-mV2PBPoSjA68g2uoKw2t+dBrerAv5cg3Z42i9n1kN80=";
};
# HASHES_END
}.${system}
27 changes: 24 additions & 3 deletions modules/kernels/cpp/language_server_clangd/default.nix
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
{ lib
, callPackage
, runCommand
, makeWrapper
, llvmPackages
, system
, cling

, kernelName
, settings
}:

let
common = callPackage ../../common.nix {};

clangd = llvmPackages.clang-tools;

cnls = callPackage ./cnls.nix { inherit system; };

cling-parser = callPackage ./cling-parser.nix { inherit cling; };

cnls-wrapped = runCommand "cpp-notebook-language-server-wrapped" {
nativeBuildInputs = [ makeWrapper ];
} ''
mkdir -p $out/bin
makeWrapper ${cnls}/bin/cpp-notebook-language-server $out/bin/cpp-notebook-language-server \
--prefix PATH : ${cling-parser}/bin
'';

languageServerName = "clangd";

passthru = {
Expand All @@ -18,7 +35,7 @@ let

in

common.writeTextDirWithMetaAndPassthru clangd.meta passthru "lib/codedown/language-servers/cpp-${kernelName}-clangd.yaml" (lib.generators.toYAML {} [{
common.writeTextDirWithMetaAndPassthru clangd.meta passthru "lib/codedown/language-servers/cpp-${kernelName}-${languageServerName}.yaml" (lib.generators.toYAML {} [{
name = languageServerName;
version = clangd.version;
extensions = ["cpp" "hpp" "cxx" "hxx" "c" "h"];
Expand All @@ -27,7 +44,11 @@ common.writeTextDirWithMetaAndPassthru clangd.meta passthru "lib/codedown/langua
type = "stream";
primary = true;
args = [
"${clangd}/bin/clangd"
];
"${cnls-wrapped}/bin/cpp-notebook-language-server"
"--wrapped-server" "${clangd}/bin/clangd"
]
++ lib.optionals settings.debug ["--log-level" "debug"]
++ lib.optionals settings.super-debug ["--debug-client-writes" "--debug-client-reads" "--debug-server-writes" "--debug-server-reads"]
;
language_id = "cpp";
}])
10 changes: 10 additions & 0 deletions modules/kernels/cpp/module.nix
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ in
type = types.bool;
default = true;
};
lsp.clangd.debug = mkOption {
example = "Clangd: enable debug output";
type = types.bool;
default = false;
};
lsp.clangd.super-debug = mkOption {
example = "Clangd: enable verbose debug output";
type = types.bool;
default = false;
};
};
};

Expand Down
1 change: 0 additions & 1 deletion tests/app/Spec/Tests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ tests =
$(getSpecFromFolder $ defaultGetSpecFromFolderOptions {
getSpecCombiner = 'describeParallel
, getSpecIndividualSpecHooks = 'withParallelSemaphore
, getSpecWarnOnParseError = NoWarnOnParseError
})
where
getQSem = getCommandLineOptions >>= liftIO . newQSem . getParallelism
Expand Down
50 changes: 26 additions & 24 deletions tests/app/Spec/Tests/Cpp.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,29 @@ import TestLib.NixTypes
import TestLib.TestSearchers
import TestLib.Types

import qualified Spec.Tests.Cpp.Completion as Completion
import qualified Spec.Tests.Cpp.Hovers as Hovers

tests :: LanguageSpec
tests = describe "C++" $ parallel $ do
testKernelSearchersBuild "cpp"
testHasExpectedFields "cpp"

-- tests' "cpp98"
-- tests' "c++11"
-- tests' "c++14"
tests' "c++17"
tests' "c++20"
tests' "c++23"
tests' "c++2c"
tests :: LanguageSpec
tests = do
describe "C++" $ do
testKernelSearchersBuild "cpp"
testHasExpectedFields "cpp"

testsWithLsp "c++23"
parallel $ do
tests' "c++17"
tests' "c++20"
tests' "c++23"
tests' "c++2c"

tests' :: Text -> LanguageSpec
tests' flavor = describe [i|C++ (#{flavor})|] $ introduceNixEnvironment [kernelSpec flavor] [] "C++" $ introduceJupyterRunner $ do
testKernelStdout "cpp" [__i|\#include <iostream>
using namespace std;
cout << "hi" << endl;|] "hi\n"
tests' flavor = describe [i|C++ (#{flavor})|] $ introduceNixEnvironment [kernelSpecWithLsp flavor] [] "C++ Nix env" $ introduceJupyterRunner $ do
describe "Kernel tests" $ do
testKernelStdout "cpp" [__i|\#include <iostream>
using namespace std;
cout << "hi" << endl;|] "hi\n"

testsWithLsp :: Text -> LanguageSpec
testsWithLsp flavor = describe [i|C++ (#{flavor}) with LSP|] $ introduceNixEnvironment [kernelSpecWithLsp flavor] [] "C++" $ do
describe "LSP" $ do
testDiagnostics'' "simple" lsName "test.cpp" LanguageKind_CPP
[__i|int main() {
Expand All @@ -49,23 +48,26 @@ testsWithLsp flavor = describe [i|C++ (#{flavor}) with LSP|] $ introduceNixEnvir
info [i|Got ranges: #{getDiagnosticRanges' diags}|]
getDiagnosticRanges' diags `shouldBe` [(Range (Position 1 2) (Position 1 20), Just (InR "undeclared_var_use"), "Use of undeclared identifier 'undefined_function'")]

Completion.tests

Hovers.tests

lsName :: Text
lsName = "clangd"

kernelSpec :: Text -> NixKernelSpec
kernelSpec flavor = kernelSpec' [[i|flavor = "#{flavor}"|]]

kernelSpecWithLsp :: Text -> NixKernelSpec
kernelSpecWithLsp flavor = kernelSpec' [
[i|flavor = "#{flavor}"|]
, "lsp.clangd.enable = true"
]
, "lsp.clangd.enable = true"
, "lsp.clangd.debug = true"
-- , "lsp.clangd.super-debug = true"
]

kernelSpec' :: [Text] -> NixKernelSpec
kernelSpec' extraConfig = NixKernelSpec {
nixKernelName = "cpp"
, nixKernelChannel = "codedown"
, nixKernelDisplayName = Just "CPP"
, nixKernelDisplayName = Just "C++"
, nixKernelPackages = []
, nixKernelMeta = Nothing
, nixKernelIcon = Nothing
Expand Down
7 changes: 7 additions & 0 deletions tests/app/Spec/Tests/Cpp/Common.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module Spec.Tests.Cpp.Common where

import Data.Text


lsName :: Text
lsName = "clangd"
56 changes: 56 additions & 0 deletions tests/app/Spec/Tests/Cpp/Completion.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
module Spec.Tests.Cpp.Completion (tests) where

import Control.Monad
import Control.Monad.IO.Unlift
import qualified Data.List as L
import Data.Maybe
import Data.String.Interpolate
import Data.Text (Text)
import qualified Data.Text as T
import Language.LSP.Protocol.Types
import Language.LSP.Test
import qualified Language.LSP.Test.Helpers as Helpers
import Spec.Tests.Cpp.Common
import Test.Sandwich as Sandwich
import Test.Sandwich.Waits (waitUntil)
import TestLib.LSP
import TestLib.Types


tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m ()
tests = describe "Completions" $ do
forM_ ["main.ipynb", "test.cpp"] $ \doc -> describe (T.unpack doc) $ do
it [i|provides std:: completions|] $ doSession' doc lsName stdCompletionCode $ \(Helpers.LspSessionInfo {..}) -> do
ident <- openDoc lspSessionInfoFileName LanguageKind_CPP

waitUntil 60 $ do
completions <- getCompletions ident (Position 2 5)
info [i|Got completions: #{completions}|]
let insertTexts = mapMaybe _insertText completions
insertTexts `listShouldContain` "iostream"
insertTexts `listShouldContain` "vector"

it [i|provides local variable completions|] $ doSession' doc lsName localVarCode $ \(Helpers.LspSessionInfo {..}) -> do
ident <- openDoc lspSessionInfoFileName LanguageKind_CPP

waitUntil 60 $ do
completions <- getCompletions ident (Position 2 2)
info [i|Got completions: #{completions}|]
let insertTexts = mapMaybe _insertText completions
insertTexts `listShouldContain` "myVariable"
insertTexts `listShouldContain` "myDouble"

stdCompletionCode :: Text
stdCompletionCode = [__i|\#include <iostream>
\#include <vector>
std::|]

localVarCode :: Text
localVarCode = [__i|int myVariable = 42;
double myDouble = 3.14;
my|]

listShouldContain :: (MonadIO m, Eq a, Show a) => [a] -> a -> m ()
listShouldContain haystack needle = case L.elem needle haystack of
True -> return ()
False -> expectationFailure [i|Expected list to contain #{show needle}, but had: #{show haystack}|]
Loading
Loading