From d5d9acbd047ee61f0dcf48cf71b8ecdd98cec172 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Tue, 13 Jan 2026 16:41:03 -0800 Subject: [PATCH 1/8] Working on packaging cpp-notebook-language-server --- modules/kernels/cpp/default.nix | 3 +- .../cpp/language_server_clangd/cnls-update.sh | 44 +++++++++++++ .../language_server_clangd/cnls-version.nix | 1 + .../cpp/language_server_clangd/cnls.nix | 33 ++++++++++ .../cpp/language_server_clangd/default.nix | 8 ++- tests/app/Spec/Tests/Cpp.hs | 10 +++ tests/app/Spec/Tests/Cpp/Common.hs | 7 +++ tests/app/Spec/Tests/Cpp/Completion.hs | 59 ++++++++++++++++++ tests/app/Spec/Tests/Cpp/Hovers.hs | 61 +++++++++++++++++++ tests/tests.cabal | 3 + 10 files changed, 226 insertions(+), 3 deletions(-) create mode 100755 modules/kernels/cpp/language_server_clangd/cnls-update.sh create mode 100644 modules/kernels/cpp/language_server_clangd/cnls-version.nix create mode 100644 modules/kernels/cpp/language_server_clangd/cnls.nix create mode 100644 tests/app/Spec/Tests/Cpp/Common.hs create mode 100644 tests/app/Spec/Tests/Cpp/Completion.hs create mode 100644 tests/app/Spec/Tests/Cpp/Hovers.hs diff --git a/modules/kernels/cpp/default.nix b/modules/kernels/cpp/default.nix index 2a42e4b..6e0124a 100644 --- a/modules/kernels/cpp/default.nix +++ b/modules/kernels/cpp/default.nix @@ -5,6 +5,7 @@ , clang , xeus-cling , llvmPackages +, system , settings , settingsSchema @@ -23,7 +24,7 @@ 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; })]; displaySuffix = { "c++17" = " 17"; diff --git a/modules/kernels/cpp/language_server_clangd/cnls-update.sh b/modules/kernels/cpp/language_server_clangd/cnls-update.sh new file mode 100755 index 0000000..d359cdd --- /dev/null +++ b/modules/kernels/cpp/language_server_clangd/cnls-update.sh @@ -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 < LanguageSpec tests' flavor = describe [i|C++ (#{flavor})|] $ introduceNixEnvironment [kernelSpec flavor] [] "C++" $ introduceJupyterRunner $ do @@ -61,6 +65,12 @@ kernelSpecWithLsp flavor = kernelSpec' [ , "lsp.clangd.enable = true" ] +testsWithCppNotebookLanguageServer :: Text -> LanguageSpec +testsWithCppNotebookLanguageServer flavor = describe [i|C++ (#{flavor}) with cpp-notebook-language-server|] $ introduceNixEnvironment [kernelSpecWithLsp flavor] [] "C++" $ do + describe "LSP" $ do + Completion.tests + Hovers.tests + kernelSpec' :: [Text] -> NixKernelSpec kernelSpec' extraConfig = NixKernelSpec { nixKernelName = "cpp" diff --git a/tests/app/Spec/Tests/Cpp/Common.hs b/tests/app/Spec/Tests/Cpp/Common.hs new file mode 100644 index 0000000..8e28aac --- /dev/null +++ b/tests/app/Spec/Tests/Cpp/Common.hs @@ -0,0 +1,7 @@ +module Spec.Tests.Cpp.Common where + +import Data.Text + + +lsName :: Text +lsName = "clangd" diff --git a/tests/app/Spec/Tests/Cpp/Completion.hs b/tests/app/Spec/Tests/Cpp/Completion.hs new file mode 100644 index 0000000..e5f59ed --- /dev/null +++ b/tests/app/Spec/Tests/Cpp/Completion.hs @@ -0,0 +1,59 @@ +module Spec.Tests.Cpp.Completion (tests) where + +import Control.Lens +import Control.Monad +import Control.Monad.IO.Unlift +import Data.String.Interpolate +import Data.Text (Text) +import Language.LSP.Protocol.Lens hiding (edit, item, range, length) +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 +import UnliftIO.Exception + + +tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m () +tests = describe "Completions" $ do + forM_ ["main.ipynb", "test.cpp"] $ \doc -> do + it [i|provides std:: completions (#{doc})|] $ doSession' doc lsName stdCompletionCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName LanguageKind_CPP + + waitUntil 60 $ + handle handleSessionException' $ do + completions <- getCompletions ident (Position 2 5) + info [i|Got completions: #{length completions} items|] + let completionLabels = map (^. label) completions + completionLabels `shouldContain` ["cout"] + completionLabels `shouldContain` ["vector"] + + it [i|provides local variable completions (#{doc})|] $ doSession' doc lsName localVarCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName LanguageKind_CPP + + waitUntil 60 $ + handle handleSessionException' $ do + completions <- getCompletions ident (Position 2 2) + info [i|Got completions: #{length completions} items|] + let completionLabels = map (^. label) completions + completionLabels `shouldContain` ["myVariable"] + completionLabels `shouldContain` ["myDouble"] + + +stdCompletionCode :: Text +stdCompletionCode = [__i|\#include + \#include + std::|] + +localVarCode :: Text +localVarCode = [__i|int myVariable = 42; + double myDouble = 3.14; + my|] + +-- | Handle potential session exceptions +handleSessionException' :: MonadIO m => SessionException -> m () +handleSessionException' (UnexpectedResponseError lspId err) = expectationFailure [i|LSP UnexpectedResponseError: #{lspId}, #{err}|] +handleSessionException' x = throwIO x diff --git a/tests/app/Spec/Tests/Cpp/Hovers.hs b/tests/app/Spec/Tests/Cpp/Hovers.hs new file mode 100644 index 0000000..f76a3c7 --- /dev/null +++ b/tests/app/Spec/Tests/Cpp/Hovers.hs @@ -0,0 +1,61 @@ +module Spec.Tests.Cpp.Hovers (tests) where + +import Control.Monad +import Control.Monad.IO.Unlift +import Data.String.Interpolate +import Data.Text (Text) +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 +import UnliftIO.Exception + + +tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m () +tests = describe "Hovers" $ do + forM_ ["main.ipynb", "test.cpp"] $ \doc -> do + it [i|hovers std::cout (#{doc})|] $ doSession' doc lsName coutCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName LanguageKind_CPP + + waitUntil 60 $ + handle handleSessionException' $ do + hover <- getHoverOrException ident (Position 1 5) + allHoverText hover `textShouldContain` [i|std::ostream|] + + it [i|hovers variable declaration (#{doc})|] $ doSession' doc lsName varDeclCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName LanguageKind_CPP + + waitUntil 60 $ + handle handleSessionException' $ do + hover <- getHoverOrException ident (Position 0 4) + allHoverText hover `textShouldContain` [i|int|] + + it [i|hovers function call (#{doc})|] $ doSession' doc lsName sqrtCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName LanguageKind_CPP + + waitUntil 60 $ + handle handleSessionException' $ do + hover <- getHoverOrException ident (Position 1 16) + allHoverText hover `textShouldContain` [i|sqrt|] + + +coutCode :: Text +coutCode = [__i|\#include + std::cout << "hello" << std::endl;|] + +varDeclCode :: Text +varDeclCode = [__i|int x = 42; + float y = 3.14;|] + +sqrtCode :: Text +sqrtCode = [__i|\#include + double result = sqrt(16.0);|] + +-- | Handle potential session exceptions +handleSessionException' :: MonadIO m => SessionException -> m () +handleSessionException' (UnexpectedResponseError lspId err) = expectationFailure [i|LSP UnexpectedResponseError: #{lspId}, #{err}|] +handleSessionException' x = throwIO x diff --git a/tests/tests.cabal b/tests/tests.cabal index 6a155a3..d00afca 100644 --- a/tests/tests.cabal +++ b/tests/tests.cabal @@ -91,6 +91,9 @@ executable tests Spec.Tests.Clojure Spec.Tests.Coq Spec.Tests.Cpp + Spec.Tests.Cpp.Common + Spec.Tests.Cpp.Completion + Spec.Tests.Cpp.Hovers Spec.Tests.Exporters Spec.Tests.Go Spec.Tests.Haskell From f20a559a637d8f5e30bf857f16b51441c303921b Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Tue, 13 Jan 2026 16:59:51 -0800 Subject: [PATCH 2/8] Package cling-parser --- modules/kernels/cpp/cling-parser.nix | 37 +++++++++++++++++++ modules/kernels/cpp/default.nix | 2 +- .../cpp/language_server_clangd/default.nix | 6 +++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 modules/kernels/cpp/cling-parser.nix diff --git a/modules/kernels/cpp/cling-parser.nix b/modules/kernels/cpp/cling-parser.nix new file mode 100644 index 0000000..2499d8c --- /dev/null +++ b/modules/kernels/cpp/cling-parser.nix @@ -0,0 +1,37 @@ +{ lib +, stdenv +, fetchFromGitHub +, cmake +, cling +, zlib +, ncurses +}: + +stdenv.mkDerivation rec { + pname = "cling-parser"; + version = "0.1.0.0"; + + src = fetchFromGitHub { + owner = "codedownio"; + repo = "cpp-notebook-language-server"; + rev = "v${version}"; + hash = "sha256-440JYZX9GE08SFsVs321eDZuDga2BadSll5lgZ5zeDE="; + }; + + 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; + }; +} diff --git a/modules/kernels/cpp/default.nix b/modules/kernels/cpp/default.nix index 6e0124a..3488a16 100644 --- a/modules/kernels/cpp/default.nix +++ b/modules/kernels/cpp/default.nix @@ -24,7 +24,7 @@ let common = callPackage ../common.nix {}; languageServers = lib.optionals settings.lsp.clangd.enable - [(callPackage ./language_server_clangd { inherit kernelName llvmPackages system; })]; + [(callPackage ./language_server_clangd { inherit kernelName llvmPackages system cling; })]; displaySuffix = { "c++17" = " 17"; diff --git a/modules/kernels/cpp/language_server_clangd/default.nix b/modules/kernels/cpp/language_server_clangd/default.nix index e7e4ad0..be93de5 100644 --- a/modules/kernels/cpp/language_server_clangd/default.nix +++ b/modules/kernels/cpp/language_server_clangd/default.nix @@ -2,6 +2,7 @@ , callPackage , llvmPackages , system +, cling , kernelName }: @@ -13,6 +14,8 @@ let cnls = callPackage ./cnls.nix { inherit system; }; + cling-parser = callPackage ../cling-parser.nix { inherit cling; }; + languageServerName = "clangd"; passthru = { @@ -33,5 +36,8 @@ common.writeTextDirWithMetaAndPassthru clangd.meta passthru "lib/codedown/langua "${cnls}/bin/cpp-notebook-language-server" "--wrapped-clangd" "${clangd}/bin/clangd" ]; + env = { + "PATH" = "${cling-parser}/bin"; + }; language_id = "cpp"; }]) From 6e77ff23f1ca91be55f043fae68e11fd9c037da2 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 14 Jan 2026 00:52:07 -0800 Subject: [PATCH 3/8] Some cnls tests passing now --- .../cpp/language_server_clangd/default.nix | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/modules/kernels/cpp/language_server_clangd/default.nix b/modules/kernels/cpp/language_server_clangd/default.nix index be93de5..8e01c65 100644 --- a/modules/kernels/cpp/language_server_clangd/default.nix +++ b/modules/kernels/cpp/language_server_clangd/default.nix @@ -1,5 +1,7 @@ { lib , callPackage +, runCommand +, makeWrapper , llvmPackages , system , cling @@ -16,6 +18,14 @@ let 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 = { @@ -33,11 +43,8 @@ common.writeTextDirWithMetaAndPassthru clangd.meta passthru "lib/codedown/langua type = "stream"; primary = true; args = [ - "${cnls}/bin/cpp-notebook-language-server" - "--wrapped-clangd" "${clangd}/bin/clangd" + "${cnls-wrapped}/bin/cpp-notebook-language-server" + "--wrapped-server" "${clangd}/bin/clangd" ]; - env = { - "PATH" = "${cling-parser}/bin"; - }; language_id = "cpp"; }]) From 7e47141a70f117d2f7350e439265375ee4c51167 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 14 Jan 2026 01:51:30 -0800 Subject: [PATCH 4/8] More work on tests --- tests/app/Spec/Tests.hs | 1 - tests/app/Spec/Tests/Cpp.hs | 52 +++++++++------------- tests/app/Spec/Tests/Cpp/Completion.hs | 47 +++++++++---------- tests/app/Spec/Tests/Cpp/Hovers.hs | 33 +++++++------- tests/src/TestLib/NixEnvironmentContext.hs | 2 +- 5 files changed, 61 insertions(+), 74 deletions(-) diff --git a/tests/app/Spec/Tests.hs b/tests/app/Spec/Tests.hs index 73392dc..d2c3873 100644 --- a/tests/app/Spec/Tests.hs +++ b/tests/app/Spec/Tests.hs @@ -32,7 +32,6 @@ tests = $(getSpecFromFolder $ defaultGetSpecFromFolderOptions { getSpecCombiner = 'describeParallel , getSpecIndividualSpecHooks = 'withParallelSemaphore - , getSpecWarnOnParseError = NoWarnOnParseError }) where getQSem = getCommandLineOptions >>= liftIO . newQSem . getParallelism diff --git a/tests/app/Spec/Tests/Cpp.hs b/tests/app/Spec/Tests/Cpp.hs index 5104835..86c5090 100644 --- a/tests/app/Spec/Tests/Cpp.hs +++ b/tests/app/Spec/Tests/Cpp.hs @@ -20,29 +20,24 @@ import qualified Spec.Tests.Cpp.Hovers as Hovers tests :: LanguageSpec -tests = describe "C++" $ parallel $ do - testKernelSearchersBuild "cpp" - testHasExpectedFields "cpp" +tests = do + describe "C++" $ 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" - - testsWithLsp "c++23" - testsWithCppNotebookLanguageServer "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 - 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 + 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() { @@ -53,29 +48,24 @@ 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" - ] - -testsWithCppNotebookLanguageServer :: Text -> LanguageSpec -testsWithCppNotebookLanguageServer flavor = describe [i|C++ (#{flavor}) with cpp-notebook-language-server|] $ introduceNixEnvironment [kernelSpecWithLsp flavor] [] "C++" $ do - describe "LSP" $ do - Completion.tests - Hovers.tests + , "lsp.clangd.enable = true" + ] kernelSpec' :: [Text] -> NixKernelSpec kernelSpec' extraConfig = NixKernelSpec { nixKernelName = "cpp" , nixKernelChannel = "codedown" - , nixKernelDisplayName = Just "CPP" + , nixKernelDisplayName = Just "C++" , nixKernelPackages = [] , nixKernelMeta = Nothing , nixKernelIcon = Nothing diff --git a/tests/app/Spec/Tests/Cpp/Completion.hs b/tests/app/Spec/Tests/Cpp/Completion.hs index e5f59ed..bef332c 100644 --- a/tests/app/Spec/Tests/Cpp/Completion.hs +++ b/tests/app/Spec/Tests/Cpp/Completion.hs @@ -1,11 +1,12 @@ module Spec.Tests.Cpp.Completion (tests) where -import Control.Lens 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 Language.LSP.Protocol.Lens hiding (edit, item, range, length) +import qualified Data.Text as T import Language.LSP.Protocol.Types import Language.LSP.Test import qualified Language.LSP.Test.Helpers as Helpers @@ -14,34 +15,30 @@ import Test.Sandwich as Sandwich import Test.Sandwich.Waits (waitUntil) import TestLib.LSP import TestLib.Types -import UnliftIO.Exception tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m () tests = describe "Completions" $ do - forM_ ["main.ipynb", "test.cpp"] $ \doc -> do - it [i|provides std:: completions (#{doc})|] $ doSession' doc lsName stdCompletionCode $ \(Helpers.LspSessionInfo {..}) -> 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 $ - handle handleSessionException' $ do - completions <- getCompletions ident (Position 2 5) - info [i|Got completions: #{length completions} items|] - let completionLabels = map (^. label) completions - completionLabels `shouldContain` ["cout"] - completionLabels `shouldContain` ["vector"] + 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 (#{doc})|] $ doSession' doc lsName localVarCode $ \(Helpers.LspSessionInfo {..}) -> do + it [i|provides local variable completions|] $ doSession' doc lsName localVarCode $ \(Helpers.LspSessionInfo {..}) -> do ident <- openDoc lspSessionInfoFileName LanguageKind_CPP - waitUntil 60 $ - handle handleSessionException' $ do - completions <- getCompletions ident (Position 2 2) - info [i|Got completions: #{length completions} items|] - let completionLabels = map (^. label) completions - completionLabels `shouldContain` ["myVariable"] - completionLabels `shouldContain` ["myDouble"] - + 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 @@ -53,7 +50,7 @@ localVarCode = [__i|int myVariable = 42; double myDouble = 3.14; my|] --- | Handle potential session exceptions -handleSessionException' :: MonadIO m => SessionException -> m () -handleSessionException' (UnexpectedResponseError lspId err) = expectationFailure [i|LSP UnexpectedResponseError: #{lspId}, #{err}|] -handleSessionException' x = throwIO x +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}|] diff --git a/tests/app/Spec/Tests/Cpp/Hovers.hs b/tests/app/Spec/Tests/Cpp/Hovers.hs index f76a3c7..33fb1bc 100644 --- a/tests/app/Spec/Tests/Cpp/Hovers.hs +++ b/tests/app/Spec/Tests/Cpp/Hovers.hs @@ -4,6 +4,7 @@ import Control.Monad import Control.Monad.IO.Unlift 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 @@ -17,22 +18,22 @@ import UnliftIO.Exception tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m () tests = describe "Hovers" $ do - forM_ ["main.ipynb", "test.cpp"] $ \doc -> do - it [i|hovers std::cout (#{doc})|] $ doSession' doc lsName coutCode $ \(Helpers.LspSessionInfo {..}) -> do - ident <- openDoc lspSessionInfoFileName LanguageKind_CPP - - waitUntil 60 $ - handle handleSessionException' $ do - hover <- getHoverOrException ident (Position 1 5) - allHoverText hover `textShouldContain` [i|std::ostream|] - - it [i|hovers variable declaration (#{doc})|] $ doSession' doc lsName varDeclCode $ \(Helpers.LspSessionInfo {..}) -> do - ident <- openDoc lspSessionInfoFileName LanguageKind_CPP - - waitUntil 60 $ - handle handleSessionException' $ do - hover <- getHoverOrException ident (Position 0 4) - allHoverText hover `textShouldContain` [i|int|] + forM_ ["main.ipynb", "test.cpp"] $ \doc -> describe (T.unpack doc) $ do + -- it [i|hovers std::cout (#{doc})|] $ doSession' doc lsName coutCode $ \(Helpers.LspSessionInfo {..}) -> do + -- ident <- openDoc lspSessionInfoFileName LanguageKind_CPP + + -- waitUntil 60 $ + -- handle handleSessionException' $ do + -- hover <- getHoverOrException ident (Position 1 6) + -- allHoverText hover `textShouldContain` [i|std::ostream|] + + -- it [i|hovers variable declaration (#{doc})|] $ doSession' doc lsName varDeclCode $ \(Helpers.LspSessionInfo {..}) -> do + -- ident <- openDoc lspSessionInfoFileName LanguageKind_CPP + + -- waitUntil 60 $ + -- handle handleSessionException' $ do + -- hover <- getHoverOrException ident (Position 0 4) + -- allHoverText hover `textShouldContain` [i|int|] it [i|hovers function call (#{doc})|] $ doSession' doc lsName sqrtCode $ \(Helpers.LspSessionInfo {..}) -> do ident <- openDoc lspSessionInfoFileName LanguageKind_CPP diff --git a/tests/src/TestLib/NixEnvironmentContext.hs b/tests/src/TestLib/NixEnvironmentContext.hs index 3a082fd..5bcfdda 100644 --- a/tests/src/TestLib/NixEnvironmentContext.hs +++ b/tests/src/TestLib/NixEnvironmentContext.hs @@ -35,7 +35,7 @@ introduceNixEnvironment :: ( -> Text -> SpecFree (LabelValue "nixEnvironment" FilePath :> context) m () -> SpecFree context m () -introduceNixEnvironment kernels otherConfig label = introduceWith' (defaultNodeOptions {nodeOptionsVisibilityThreshold = 50}) [i|#{label}|] nixEnvironment $ \action -> do +introduceNixEnvironment kernels otherConfig label = introduceWith' (defaultNodeOptions {nodeOptionsVisibilityThreshold = 60}) [i|#{label}|] nixEnvironment $ \action -> do rootDir <- findFirstParentMatching (\x -> doesPathExist (x ".git")) metadata :: A.Object <- bracket (openFile "/dev/null" WriteMode) hClose $ \devNullHandle -> do From 143d3483c175d48fa217a87800327e5ce8813fde Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 14 Jan 2026 01:52:24 -0800 Subject: [PATCH 5/8] More --- tests/app/Spec/Tests/Cpp/Hovers.hs | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/tests/app/Spec/Tests/Cpp/Hovers.hs b/tests/app/Spec/Tests/Cpp/Hovers.hs index 33fb1bc..0f23254 100644 --- a/tests/app/Spec/Tests/Cpp/Hovers.hs +++ b/tests/app/Spec/Tests/Cpp/Hovers.hs @@ -22,26 +22,23 @@ tests = describe "Hovers" $ do -- it [i|hovers std::cout (#{doc})|] $ doSession' doc lsName coutCode $ \(Helpers.LspSessionInfo {..}) -> do -- ident <- openDoc lspSessionInfoFileName LanguageKind_CPP - -- waitUntil 60 $ - -- handle handleSessionException' $ do - -- hover <- getHoverOrException ident (Position 1 6) - -- allHoverText hover `textShouldContain` [i|std::ostream|] + -- waitUntil 60 $ do + -- hover <- getHoverOrException ident (Position 1 6) + -- allHoverText hover `textShouldContain` [i|std::ostream|] -- it [i|hovers variable declaration (#{doc})|] $ doSession' doc lsName varDeclCode $ \(Helpers.LspSessionInfo {..}) -> do -- ident <- openDoc lspSessionInfoFileName LanguageKind_CPP - -- waitUntil 60 $ - -- handle handleSessionException' $ do - -- hover <- getHoverOrException ident (Position 0 4) - -- allHoverText hover `textShouldContain` [i|int|] + -- waitUntil 60 $ do + -- hover <- getHoverOrException ident (Position 0 4) + -- allHoverText hover `textShouldContain` [i|int|] it [i|hovers function call (#{doc})|] $ doSession' doc lsName sqrtCode $ \(Helpers.LspSessionInfo {..}) -> do ident <- openDoc lspSessionInfoFileName LanguageKind_CPP - waitUntil 60 $ - handle handleSessionException' $ do - hover <- getHoverOrException ident (Position 1 16) - allHoverText hover `textShouldContain` [i|sqrt|] + waitUntil 60 $ do + hover <- getHoverOrException ident (Position 1 16) + allHoverText hover `textShouldContain` [i|sqrt|] coutCode :: Text @@ -55,8 +52,3 @@ varDeclCode = [__i|int x = 42; sqrtCode :: Text sqrtCode = [__i|\#include double result = sqrt(16.0);|] - --- | Handle potential session exceptions -handleSessionException' :: MonadIO m => SessionException -> m () -handleSessionException' (UnexpectedResponseError lspId err) = expectationFailure [i|LSP UnexpectedResponseError: #{lspId}, #{err}|] -handleSessionException' x = throwIO x From c251df39267c9573ace221f7f4447635161349d4 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 14 Jan 2026 03:23:28 -0800 Subject: [PATCH 6/8] Add clangd debugging flags --- modules/kernels/cpp/default.nix | 5 ++++- modules/kernels/cpp/language_server_clangd/default.nix | 6 +++++- modules/kernels/cpp/module.nix | 10 ++++++++++ tests/app/Spec/Tests/Cpp.hs | 2 ++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/modules/kernels/cpp/default.nix b/modules/kernels/cpp/default.nix index 3488a16..9d5a58a 100644 --- a/modules/kernels/cpp/default.nix +++ b/modules/kernels/cpp/default.nix @@ -24,7 +24,10 @@ let common = callPackage ../common.nix {}; languageServers = lib.optionals settings.lsp.clangd.enable - [(callPackage ./language_server_clangd { inherit kernelName llvmPackages system cling; })]; + [(callPackage ./language_server_clangd { + inherit kernelName llvmPackages system cling; + settings = settings.lsp.clangd; + })]; displaySuffix = { "c++17" = " 17"; diff --git a/modules/kernels/cpp/language_server_clangd/default.nix b/modules/kernels/cpp/language_server_clangd/default.nix index 8e01c65..f781a28 100644 --- a/modules/kernels/cpp/language_server_clangd/default.nix +++ b/modules/kernels/cpp/language_server_clangd/default.nix @@ -7,6 +7,7 @@ , cling , kernelName +, settings }: let @@ -45,6 +46,9 @@ common.writeTextDirWithMetaAndPassthru clangd.meta passthru "lib/codedown/langua args = [ "${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"; }]) diff --git a/modules/kernels/cpp/module.nix b/modules/kernels/cpp/module.nix index fc9943a..217ffe5 100644 --- a/modules/kernels/cpp/module.nix +++ b/modules/kernels/cpp/module.nix @@ -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; + }; }; }; diff --git a/tests/app/Spec/Tests/Cpp.hs b/tests/app/Spec/Tests/Cpp.hs index 86c5090..3d8aeb1 100644 --- a/tests/app/Spec/Tests/Cpp.hs +++ b/tests/app/Spec/Tests/Cpp.hs @@ -59,6 +59,8 @@ kernelSpecWithLsp :: Text -> NixKernelSpec kernelSpecWithLsp flavor = kernelSpec' [ [i|flavor = "#{flavor}"|] , "lsp.clangd.enable = true" + , "lsp.clangd.debug = true" + -- , "lsp.clangd.super-debug = true" ] kernelSpec' :: [Text] -> NixKernelSpec From b9caa85e7f80c67ca802bcc4161727a6ac689faf Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Fri, 16 Jan 2026 14:37:20 -0800 Subject: [PATCH 7/8] Bump cnls to 0.1.0.1 --- .../cling-parser.nix | 4 ++-- .../language_server_clangd/cnls-version.nix | 2 +- .../cpp/language_server_clangd/cnls.nix | 24 +++++++++---------- .../cpp/language_server_clangd/default.nix | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) rename modules/kernels/cpp/{ => language_server_clangd}/cling-parser.nix (87%) diff --git a/modules/kernels/cpp/cling-parser.nix b/modules/kernels/cpp/language_server_clangd/cling-parser.nix similarity index 87% rename from modules/kernels/cpp/cling-parser.nix rename to modules/kernels/cpp/language_server_clangd/cling-parser.nix index 2499d8c..aa0bf90 100644 --- a/modules/kernels/cpp/cling-parser.nix +++ b/modules/kernels/cpp/language_server_clangd/cling-parser.nix @@ -9,13 +9,13 @@ stdenv.mkDerivation rec { pname = "cling-parser"; - version = "0.1.0.0"; + version = import ./cnls-version.nix; src = fetchFromGitHub { owner = "codedownio"; repo = "cpp-notebook-language-server"; rev = "v${version}"; - hash = "sha256-440JYZX9GE08SFsVs321eDZuDga2BadSll5lgZ5zeDE="; + hash = "sha256-WuGEvLF/6OqZFc0xBspyb/NRjvBL7khGG7C90LznOHQ="; }; sourceRoot = "${src.name}/cling-parser"; diff --git a/modules/kernels/cpp/language_server_clangd/cnls-version.nix b/modules/kernels/cpp/language_server_clangd/cnls-version.nix index 94cad58..bc5a2b2 100644 --- a/modules/kernels/cpp/language_server_clangd/cnls-version.nix +++ b/modules/kernels/cpp/language_server_clangd/cnls-version.nix @@ -1 +1 @@ -"0.1.0.0" +"0.1.0.1" diff --git a/modules/kernels/cpp/language_server_clangd/cnls.nix b/modules/kernels/cpp/language_server_clangd/cnls.nix index 33020ef..74caff7 100644 --- a/modules/kernels/cpp/language_server_clangd/cnls.nix +++ b/modules/kernels/cpp/language_server_clangd/cnls.nix @@ -6,28 +6,28 @@ { # HASHES_START "aarch64-linux" = fetchzip { - name = "cpp-notebook-language-server-0.1.0.0"; + name = "cpp-notebook-language-server-0.1.0.1"; stripRoot = false; - url = "https://github.com/codedownio/cpp-notebook-language-server/releases/download/v0.1.0.0/cpp-notebook-language-server-0.1.0.0-aarch64-linux.tar.gz"; - hash = "sha256-1WefJo6tqUJYDo/6xOufNigqyf5LiTpJ2CqiZIcmJmY="; + url = "https://github.com/codedownio/cpp-notebook-language-server/releases/download/v0.1.0.1/cpp-notebook-language-server-0.1.0.1-aarch64-linux.tar.gz"; + hash = "sha256-HA+V1s7VdKztyptT7TRnH2SpohaPhfo/NTfO0iFt4jY="; }; "x86_64-linux" = fetchzip { - name = "cpp-notebook-language-server-0.1.0.0"; + name = "cpp-notebook-language-server-0.1.0.1"; stripRoot = false; - url = "https://github.com/codedownio/cpp-notebook-language-server/releases/download/v0.1.0.0/cpp-notebook-language-server-0.1.0.0-x86_64-linux.tar.gz"; - hash = "sha256-75D4oKFwYOxCg5BwCi1UqWjtf1wXU79wez8kcclWrWw="; + url = "https://github.com/codedownio/cpp-notebook-language-server/releases/download/v0.1.0.1/cpp-notebook-language-server-0.1.0.1-x86_64-linux.tar.gz"; + hash = "sha256-N1/FK14ILBfjQyN7fO2DH5IYlNk2AmzVJLn3dIMkLR8="; }; "x86_64-darwin" = fetchzip { - name = "cpp-notebook-language-server-0.1.0.0"; + name = "cpp-notebook-language-server-0.1.0.1"; stripRoot = false; - url = "https://github.com/codedownio/cpp-notebook-language-server/releases/download/v0.1.0.0/cpp-notebook-language-server-0.1.0.0-x86_64-darwin.tar.gz"; - hash = "sha256-aAco6+QlFYtx9RAOTctFHgVvXRzreZHlNHROvi0/Vxs="; + url = "https://github.com/codedownio/cpp-notebook-language-server/releases/download/v0.1.0.1/cpp-notebook-language-server-0.1.0.1-x86_64-darwin.tar.gz"; + hash = "sha256-Hf9x95lh6p1sKHTuSEZeyve6UumH/S6lAFgITzBeH7Q="; }; "aarch64-darwin" = fetchzip { - name = "cpp-notebook-language-server-0.1.0.0"; + name = "cpp-notebook-language-server-0.1.0.1"; stripRoot = false; - url = "https://github.com/codedownio/cpp-notebook-language-server/releases/download/v0.1.0.0/cpp-notebook-language-server-0.1.0.0-aarch64-darwin.tar.gz"; - hash = "sha256-ZIXrKcJQeTcyM8lXWp6+1ZCbywvBJRXoi6VC670G5Yw="; + url = "https://github.com/codedownio/cpp-notebook-language-server/releases/download/v0.1.0.1/cpp-notebook-language-server-0.1.0.1-aarch64-darwin.tar.gz"; + hash = "sha256-E5rHMQ4yCSjclxPOIPJirYR5odU94I/Kvtok8SOE0Hg="; }; # HASHES_END }.${system} diff --git a/modules/kernels/cpp/language_server_clangd/default.nix b/modules/kernels/cpp/language_server_clangd/default.nix index f781a28..4e3ac3f 100644 --- a/modules/kernels/cpp/language_server_clangd/default.nix +++ b/modules/kernels/cpp/language_server_clangd/default.nix @@ -17,7 +17,7 @@ let cnls = callPackage ./cnls.nix { inherit system; }; - cling-parser = callPackage ../cling-parser.nix { inherit cling; }; + cling-parser = callPackage ./cling-parser.nix { inherit cling; }; cnls-wrapped = runCommand "cpp-notebook-language-server-wrapped" { nativeBuildInputs = [ makeWrapper ]; From f085d926c585e355e12f1dce1982eb839487c734 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Sat, 17 Jan 2026 03:09:35 -0800 Subject: [PATCH 8/8] Bump cnls to 0.1.0.2 --- .../language_server_clangd/cling-parser.nix | 2 +- .../language_server_clangd/cnls-version.nix | 2 +- .../cpp/language_server_clangd/cnls.nix | 24 +++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/modules/kernels/cpp/language_server_clangd/cling-parser.nix b/modules/kernels/cpp/language_server_clangd/cling-parser.nix index aa0bf90..f7def87 100644 --- a/modules/kernels/cpp/language_server_clangd/cling-parser.nix +++ b/modules/kernels/cpp/language_server_clangd/cling-parser.nix @@ -15,7 +15,7 @@ stdenv.mkDerivation rec { owner = "codedownio"; repo = "cpp-notebook-language-server"; rev = "v${version}"; - hash = "sha256-WuGEvLF/6OqZFc0xBspyb/NRjvBL7khGG7C90LznOHQ="; + hash = "sha256-+Af5Rn03iaV5JcKVr8625YPOjqZx8Pf/4Chv6bqcwJY="; }; sourceRoot = "${src.name}/cling-parser"; diff --git a/modules/kernels/cpp/language_server_clangd/cnls-version.nix b/modules/kernels/cpp/language_server_clangd/cnls-version.nix index bc5a2b2..a201a92 100644 --- a/modules/kernels/cpp/language_server_clangd/cnls-version.nix +++ b/modules/kernels/cpp/language_server_clangd/cnls-version.nix @@ -1 +1 @@ -"0.1.0.1" +"0.1.0.2" diff --git a/modules/kernels/cpp/language_server_clangd/cnls.nix b/modules/kernels/cpp/language_server_clangd/cnls.nix index 74caff7..4fc83f0 100644 --- a/modules/kernels/cpp/language_server_clangd/cnls.nix +++ b/modules/kernels/cpp/language_server_clangd/cnls.nix @@ -6,28 +6,28 @@ { # HASHES_START "aarch64-linux" = fetchzip { - name = "cpp-notebook-language-server-0.1.0.1"; + 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.1/cpp-notebook-language-server-0.1.0.1-aarch64-linux.tar.gz"; - hash = "sha256-HA+V1s7VdKztyptT7TRnH2SpohaPhfo/NTfO0iFt4jY="; + 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.1"; + 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.1/cpp-notebook-language-server-0.1.0.1-x86_64-linux.tar.gz"; - hash = "sha256-N1/FK14ILBfjQyN7fO2DH5IYlNk2AmzVJLn3dIMkLR8="; + 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.1"; + 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.1/cpp-notebook-language-server-0.1.0.1-x86_64-darwin.tar.gz"; - hash = "sha256-Hf9x95lh6p1sKHTuSEZeyve6UumH/S6lAFgITzBeH7Q="; + 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.1"; + 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.1/cpp-notebook-language-server-0.1.0.1-aarch64-darwin.tar.gz"; - hash = "sha256-E5rHMQ4yCSjclxPOIPJirYR5odU94I/Kvtok8SOE0Hg="; + 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}