From 2a72c8669e872c24bd7c3cd43ec43df9d5a5f6be Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Fri, 9 Jan 2026 19:38:47 -0800 Subject: [PATCH 1/5] Working on moving LSP test code out to lsp-test-helpers noci --- tests/app/Spec/Tests/Bash.hs | 2 +- tests/app/Spec/Tests/Clojure.hs | 2 +- tests/app/Spec/Tests/Cpp.hs | 2 +- tests/app/Spec/Tests/Go.hs | 2 +- tests/app/Spec/Tests/Haskell/Diagnostics.hs | 12 +- tests/app/Spec/Tests/Haskell/Statements.hs | 4 +- tests/app/Spec/Tests/Julia.hs | 2 +- tests/app/Spec/Tests/Julia/Diagnostics.hs | 8 +- tests/app/Spec/Tests/Python.hs | 14 +- tests/app/Spec/Tests/Ruby.hs | 2 +- tests/app/Spec/Tests/Rust/Diagnostics.hs | 18 +- tests/app/Spec/Tests/Spellchecker.hs | 10 +- tests/app/Spec/Tests/Typst.hs | 2 +- tests/src/TestLib/LSP.hs | 277 +++++--------------- tests/stack.yaml | 5 + 15 files changed, 103 insertions(+), 259 deletions(-) diff --git a/tests/app/Spec/Tests/Bash.hs b/tests/app/Spec/Tests/Bash.hs index 5de80c4d..9b347d25 100644 --- a/tests/app/Spec/Tests/Bash.hs +++ b/tests/app/Spec/Tests/Bash.hs @@ -37,7 +37,7 @@ tests = describe "Bash" $ introduceNixEnvironment [kernelSpec] [] "Bash" $ intro -- |] $ \diagnostics -> do -- assertDiagnosticRanges diagnostics [] - testDiagnostics "bash-language-server" "test.sh" Nothing [__i|FOO=42|] $ \diagnostics -> do + testDiagnostics "bash-language-server" "test.sh" [__i|FOO=42|] $ \diagnostics -> do assertDiagnosticRanges diagnostics [ (Range (Position 0 0) (Position 0 3), Just (InR "SC2034")) ] diff --git a/tests/app/Spec/Tests/Clojure.hs b/tests/app/Spec/Tests/Clojure.hs index 30105ebc..1a027d2b 100644 --- a/tests/app/Spec/Tests/Clojure.hs +++ b/tests/app/Spec/Tests/Clojure.hs @@ -31,7 +31,7 @@ tests = describe "Clojure" $ introduceNixEnvironment [kernelSpec] [] "Clojure" $ testKernelStdout "clojure" [__i|(println "hi")|] "hi\n" - testDiagnostics "clojure-lsp" "test.clj" Nothing [__i|(foo 42)|] $ \diagnostics -> do + testDiagnostics "clojure-lsp" "test.clj" [__i|(foo 42)|] $ \diagnostics -> do assertDiagnosticRanges diagnostics [(Range (Position 0 1) (Position 0 4), Just (InR "unresolved-symbol"))] diff --git a/tests/app/Spec/Tests/Cpp.hs b/tests/app/Spec/Tests/Cpp.hs index 6d6022bc..1120d69f 100644 --- a/tests/app/Spec/Tests/Cpp.hs +++ b/tests/app/Spec/Tests/Cpp.hs @@ -40,7 +40,7 @@ tests' flavor = describe [i|C++ (#{flavor})|] $ introduceNixEnvironment [kernelS testsWithLsp :: Text -> LanguageSpec testsWithLsp flavor = describe [i|C++ (#{flavor}) with LSP|] $ introduceNixEnvironment [kernelSpecWithLsp flavor] [] "C++" $ do describe "LSP" $ do - testDiagnostics'' "simple" lsName "test.cpp" (Just "cpp") + testDiagnostics'' "simple" lsName "test.cpp" [__i|int main() { undefined_function(); return 0; diff --git a/tests/app/Spec/Tests/Go.hs b/tests/app/Spec/Tests/Go.hs index da4554c6..521b86d7 100644 --- a/tests/app/Spec/Tests/Go.hs +++ b/tests/app/Spec/Tests/Go.hs @@ -33,7 +33,7 @@ tests = describe "Go" $ introduceNixEnvironment [kernelSpec] [] "Go" $ introduce testKernelStdout "go" [__i|import("fmt") fmt.Println("hi")|] "hi\n" - testDiagnosticsLabel "gopls: Undeclared name" "gopls" "test.go" Nothing printUnknownCode $ \diagnostics -> + testDiagnosticsLabel "gopls: Undeclared name" "gopls" "test.go" printUnknownCode $ \diagnostics -> assertDiagnosticRanges diagnostics [(Range (Position 3 12) (Position 3 15), Just (InR "UndeclaredName"))] printUnknownCode :: Text diff --git a/tests/app/Spec/Tests/Haskell/Diagnostics.hs b/tests/app/Spec/Tests/Haskell/Diagnostics.hs index 6b218442..26619d52 100644 --- a/tests/app/Spec/Tests/Haskell/Diagnostics.hs +++ b/tests/app/Spec/Tests/Haskell/Diagnostics.hs @@ -27,18 +27,18 @@ import TestLib.Types tests :: (LspContext context m, HasNixEnvironment context) => Text -> Text -> SpecFree context m () tests ghcPackage lsName = describe "Diagnostics" $ do describe "Foo.hs" $ do - testDiagnosticsLabelDesired "Out of scope variable" lsName "Foo.hs" Nothing + testDiagnosticsLabelDesired "Out of scope variable" lsName "Foo.hs" [__i|module Foo where foo = bar |] ((== [(Range (Position 1 6) (Position 1 9), Just (InR "GHC-88464"))]) . getDiagnosticRanges) when (ghcPackage /= "ghc910") $ -- TODO: re-enable hlint test - testDiagnosticsLabelDesired "Eta reduce" lsName "Foo.hs" Nothing etaExpandCode + testDiagnosticsLabelDesired "Eta reduce" lsName "Foo.hs" etaExpandCode ((== [(Range (Position 6 0) (Position 6 14), Just (InR "refact:Eta reduce"))]) . getDiagnosticRanges) describe "main.ipynb" $ do - testDiagnosticsLabelDesired "Top-level putStrLn" lsName "main.ipynb" Nothing + testDiagnosticsLabelDesired "Top-level putStrLn" lsName "main.ipynb" [__i|-- A comment foo = bar @@ -46,7 +46,7 @@ tests ghcPackage lsName = describe "Diagnostics" $ do |] ((== [(Range (Position 1 6) (Position 1 9), Just (InR "GHC-88464"))]) . getDiagnosticRanges) - testDiagnosticsLabel "Top-level putStrLn with diagnostic" lsName "main.ipynb" Nothing + testDiagnosticsLabel "Top-level putStrLn with diagnostic" lsName "main.ipynb" [__i|-- Some comment import Data.ByteString.Lazy.Char8 as BL foo = bar @@ -56,7 +56,7 @@ tests ghcPackage lsName = describe "Diagnostics" $ do [(Range (Position 4 0) (Position 4 8), x)] | containsAll x ["Ambiguous occurrence", "putStrLn"] -> return () xs -> expectationFailure [i|Unexpected diagnostics: #{xs}|] - testDiagnosticsLabelDesired "Reordering" lsName "main.ipynb" Nothing + testDiagnosticsLabelDesired "Reordering" lsName "main.ipynb" [__i|import Data.Aeson.TH {-\# LANGUAGE TemplateHaskell \#-} foo = bar -- This should be the only diagnostic we get @@ -64,7 +64,7 @@ tests ghcPackage lsName = describe "Diagnostics" $ do $(deriveJSON defaultOptions ''Foo)|] ((== [(Range (Position 2 6) (Position 2 9), Just (InR "GHC-88464"))]) . getDiagnosticRanges) - testDiagnosticsLabelDesired "Complicated reordering" lsName "main.ipynb" Nothing + testDiagnosticsLabelDesired "Complicated reordering" lsName "main.ipynb" [__i|import Data.Aeson as A import Data.Aeson.TH :set -XTemplateHaskell diff --git a/tests/app/Spec/Tests/Haskell/Statements.hs b/tests/app/Spec/Tests/Haskell/Statements.hs index 3f11f6e1..c75522e2 100644 --- a/tests/app/Spec/Tests/Haskell/Statements.hs +++ b/tests/app/Spec/Tests/Haskell/Statements.hs @@ -22,7 +22,7 @@ tests ghcPackage = describe "Statements" $ do timeout 120_000_000 (getHighlights ident (Position 0 1)) >>= (`shouldBe` (Just documentHighlightResults)) when (ghcPackage /= "ghc910") $ -- TODO: re-enable hlint test - testDiagnosticsLabel "Empty diagnostics" lsName "main.ipynb" Nothing statementsCode $ \diagnostics -> do + testDiagnosticsLabel "Empty diagnostics" lsName "main.ipynb" statementsCode $ \diagnostics -> do -- Note: normally the server wouldn't send empty diagnostics. But the statement inserts "= unsafePerformIO $ ", -- which causes it to emit a "redundant bracket" diagnostic, which then gets filtered out by untransformPosition diagnostics `shouldBe` [] @@ -33,7 +33,7 @@ tests ghcPackage = describe "Statements" $ do timeout 120_000_000 (getHighlights ident (Position 0 1)) >>= (`shouldBe` (Just documentHighlightResults)) when (ghcPackage /= "ghc910") $ -- TODO: re-enable hlint test - testDiagnosticsLabel "Redundant bracket" lsName "main.ipynb" Nothing statementsCodeMultiline $ \diagnostics -> do + testDiagnosticsLabel "Redundant bracket" lsName "main.ipynb" statementsCodeMultiline $ \diagnostics -> do info [i|Got diagnostics: #{diagnostics}|] assertDiagnosticRanges diagnostics [(Range (Position 1 9) (Position 1 14), Just (InR "refact:Redundant bracket"))] diff --git a/tests/app/Spec/Tests/Julia.hs b/tests/app/Spec/Tests/Julia.hs index c44a4640..a5b780c0 100644 --- a/tests/app/Spec/Tests/Julia.hs +++ b/tests/app/Spec/Tests/Julia.hs @@ -45,7 +45,7 @@ juliaTests juliaPackage = describe [i|Julia (#{juliaPackage})|] $ introduceNixEn describe "LSP" $ do Diagnostics.tests lsName - itHasHoverSatisfying lsName "test.jl" (Just "julia") [__i|print("hi")|] (Position 0 2) $ \hover -> do + itHasHoverSatisfying lsName "test.jl" [__i|print("hi")|] (Position 0 2) $ \hover -> do let InL (MarkupContent MarkupKind_Markdown text) = hover ^. contents text `textShouldContain` "Write to `io` (or to the default output stream" diff --git a/tests/app/Spec/Tests/Julia/Diagnostics.hs b/tests/app/Spec/Tests/Julia/Diagnostics.hs index 1a91775c..60410eb8 100644 --- a/tests/app/Spec/Tests/Julia/Diagnostics.hs +++ b/tests/app/Spec/Tests/Julia/Diagnostics.hs @@ -13,10 +13,10 @@ import TestLib.Types tests :: (LspContext context m, HasNixEnvironment context) => Text -> SpecFree context m () tests lsName = describe "Diagnostics" $ do - testDiagnostics'' "flags a simple missing reference" lsName "test.jl" (Just "julia") [i|printlnzzzz("HI")|] [] $ \diagnostics -> do + testDiagnostics'' "flags a simple missing reference" lsName "test.jl" [i|printlnzzzz("HI")|] [] $ \diagnostics -> do assertDiagnosticRanges' diagnostics [(Range (Position 0 0) (Position 0 11), Nothing, "Missing reference: printlnzzzz")] - testDiagnosticsLabelDesired "finds symbols from JSON3 package" lsName "test.jl" (Just "julia") + testDiagnosticsLabelDesired "finds symbols from JSON3 package" lsName "test.jl" [__i|using JSON3: write tup = (:car,"Mercedes","S500",5,250.1) write(tup) @@ -24,7 +24,7 @@ tests lsName = describe "Diagnostics" $ do |] ((== [(Range (Position 3 0) (Position 3 11), Nothing, "Missing reference: printlnzzzz")]) . getDiagnosticRanges') - testDiagnosticsLabelDesired "finds symbols from Roots package" lsName "test.jl" (Just "julia") + testDiagnosticsLabelDesired "finds symbols from Roots package" lsName "test.jl" [__i|using Roots: Bisection, find_zero f(x) = exp(x) - x^4 find_zero(f, (8, 9), Bisection()) @@ -34,7 +34,7 @@ tests lsName = describe "Diagnostics" $ do -- This test is tricky because symbols like "plot" actually come from RecipesBase (or something), so -- it checks we're indexing such a transitive dependency. - testDiagnosticsLabelDesired "finds symbols from Plots package" lsName "test.jl" (Just "julia") + testDiagnosticsLabelDesired "finds symbols from Plots package" lsName "test.jl" [__i|using Plots: plot, plot! xx = range(0, 10, length=100) y = sin.(xx) diff --git a/tests/app/Spec/Tests/Python.hs b/tests/app/Spec/Tests/Python.hs index d8a7f8e9..66345543 100644 --- a/tests/app/Spec/Tests/Python.hs +++ b/tests/app/Spec/Tests/Python.hs @@ -35,17 +35,17 @@ tests' (kernelName, pythonPackage) = introduceNixEnvironment [kernelSpec kernelN testKernelStdout "python3" [i|print(42)|] "42\n" testKernelStdout' "python3" [i|import scipy|] Nothing - testDiagnostics "python-lsp-server" "test.py" Nothing [i|\n\n\nfoo = 42|] $ \diagnostics -> do + testDiagnostics "python-lsp-server" "test.py" [i|\n\n\nfoo = 42|] $ \diagnostics -> do assertDiagnosticRanges diagnostics [] - testDiagnostics "pylint" "test.py" Nothing [i|\n\n\nfoo = 42|] $ \diagnostics -> do + testDiagnostics "pylint" "test.py" [i|\n\n\nfoo = 42|] $ \diagnostics -> do assertDiagnosticRanges' diagnostics [ (Range (Position 3 0) (Position 3 0), Nothing, "Final newline missing (C0304:missing-final-newline)") , (Range (Position 0 0) (Position 0 0), Nothing, "Missing module docstring (C0114:missing-module-docstring)") , (Range (Position 3 0) (Position 3 0), Nothing, "Disallowed name \"foo\" (C0104:disallowed-name)") ] - testDiagnostics "pyright" "test.py" Nothing [__i|\# pyright: strict + testDiagnostics "pyright" "test.py" [__i|\# pyright: strict def f(x: int, y: str) -> None: z = 1.0 f("asdf", 42) @@ -61,10 +61,10 @@ tests' (kernelName, pythonPackage) = introduceNixEnvironment [kernelSpec kernelN , (Range (Position 2 2) (Position 2 3), Just (InR "reportUnusedVariable"), "Variable \"z\" is not accessed") ] - testDiagnostics "pycodestyle" "test.py" Nothing [__i|def f(x: int, y: str) -> None: - z = 1.0 - f("asdf", 42) - |] $ \diagnostics -> do + testDiagnostics "pycodestyle" "test.py" [__i|def f(x: int, y: str) -> None: + z = 1.0 + f("asdf", 42) + |] $ \diagnostics -> do assertDiagnosticRanges diagnostics [] diff --git a/tests/app/Spec/Tests/Ruby.hs b/tests/app/Spec/Tests/Ruby.hs index 407c5bec..af5f57f1 100644 --- a/tests/app/Spec/Tests/Ruby.hs +++ b/tests/app/Spec/Tests/Ruby.hs @@ -49,7 +49,7 @@ kernelTests rubyPackage = do info [i|RUBY_VERSION result: #{t}|] t `textShouldContain` versionString - itHasHoverSatisfying "solargraph" "test.rb" Nothing [__i|puts "hi"|] (Position 0 2) $ \hover -> do + itHasHoverSatisfying "solargraph" "test.rb" [__i|puts "hi"|] (Position 0 2) $ \hover -> do let InL (MarkupContent MarkupKind_Markdown text) = hover ^. contents text `textShouldContain` "Kernel#puts" text `textShouldContain` "$stdout.puts(obj" diff --git a/tests/app/Spec/Tests/Rust/Diagnostics.hs b/tests/app/Spec/Tests/Rust/Diagnostics.hs index cc43fc92..1fbc1150 100644 --- a/tests/app/Spec/Tests/Rust/Diagnostics.hs +++ b/tests/app/Spec/Tests/Rust/Diagnostics.hs @@ -14,16 +14,16 @@ import TestLib.Types tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m () tests = describe "Diagnostics" $ do - testDiagnostics "rust-analyzer" "main.ipynb" Nothing [__i|printlnz!("Hello world"); - |] $ \diagnostics -> do + testDiagnostics "rust-analyzer" "main.ipynb" [__i|printlnz!("Hello world"); + |] $ \diagnostics -> do assertDiagnosticRanges' diagnostics [ (Range (Position 0 0) (Position 0 8), Nothing, "cannot find macro `printlnz` in this scope") , (Range (Position 0 0) (Position 0 8), Nothing, "a macro with a similar name exists: `println`") ] - testDiagnostics "rust-analyzer" "test.rs" Nothing [__i|struct A { a: u8, b: u8 } - const a: A = A { a: 10, }; - |] $ \diagnostics -> do + testDiagnostics "rust-analyzer" "test.rs" [__i|struct A { a: u8, b: u8 } + const a: A = A { a: 10, }; + |] $ \diagnostics -> do assertDiagnosticRanges' (L.sortBy (compare `on` (^. LSP.message)) diagnostics) [ (Range (Position 1 13) (Position 1 14), Just (InR "E0063"), "missing field `b` in initializer of `A`\nmissing `b`") -- (Range (Position 1 6) (Position 1 7), Just (InR "non_upper_case_globals"), "Constant `a` should have UPPER_SNAKE_CASE name, e.g. `A`") @@ -31,10 +31,10 @@ tests = describe "Diagnostics" $ do -- , (Range (Position 1 13) (Position 1 14), Just (InR "E0063"), "missing structure fields:\n- b\n") ] - testDiagnostics "rust-analyzer" "main.ipynb" Nothing [__i|println!("Hello world"); - eprintln!("Hello error"); - format!("Hello {}", "world") - |] $ \diagnostics -> do + testDiagnostics "rust-analyzer" "main.ipynb" [__i|println!("Hello world"); + eprintln!("Hello error"); + format!("Hello {}", "world") + |] $ \diagnostics -> do assertDiagnosticRanges' (L.sortBy (compare `on` (^. LSP.message)) diagnostics) [ (Range (Position 2 0) (Position 2 28), Just (InR "E0308"), "mismatched types\nexpected `()`, found `String`") ] diff --git a/tests/app/Spec/Tests/Spellchecker.hs b/tests/app/Spec/Tests/Spellchecker.hs index 6aee19be..034a836b 100644 --- a/tests/app/Spec/Tests/Spellchecker.hs +++ b/tests/app/Spec/Tests/Spellchecker.hs @@ -29,9 +29,7 @@ otherConfig = [ tests :: TopSpec tests = describe "Spellchecker" $ introduceNixEnvironment [] otherConfig "Spellchecker env" $ introduceJustBubblewrap $ do it "Gets diagnostics and a working code action" $ do - lspConfig <- findLspConfig "spellchecker" - (pathToUse, closure) <- getPathAndNixEnvironmentClosure - withLspSession lspConfig pathToUse closure "test.md" [i|\# This is mispelled|] [] $ \lspHomeDir -> do + doSession'' "test.md" "spellchecker" [i|\# This is mispelled|] [] $ \lspHomeDir -> do ident <- openDoc "test.md" "spellchecker" waitUntil 300.0 $ do diagnostics <- waitForDiagnostics @@ -51,16 +49,14 @@ tests = describe "Spellchecker" $ introduceNixEnvironment [] otherConfig "Spellc liftIO (T.readFile datPath) >>= (`shouldBe` "mispelled\n") it "Uses a personal dictionary on startup" $ do - lspConfig <- findLspConfig "spellchecker" - (pathToUse, closure) <- getPathAndNixEnvironmentClosure let extraFiles = [(".codedown/personal-dictionary.dat", "mispelled\n")] - withLspSession' id lspConfig pathToUse closure "test.md" [i|\# This is mispelled|] extraFiles $ \_homeDir -> do + doSession'' "test.md" "spellchecker" [i|\# This is mispelled|] extraFiles $ \_homeDir -> do _ident <- openDoc "test.md" "spellchecker" waitUntil 300.0 $ do diagnostics <- waitForDiagnostics lift $ assertDiagnosticRanges diagnostics [] - testDiagnostics "spellchecker" "test.md" Nothing [i|I've done a thing.|] $ \diagnostics -> do + testDiagnostics "spellchecker" "test.md" [i|I've done a thing.|] $ \diagnostics -> do assertDiagnosticRanges diagnostics [] diff --git a/tests/app/Spec/Tests/Typst.hs b/tests/app/Spec/Tests/Typst.hs index b5f1cbe7..2f4ebfad 100644 --- a/tests/app/Spec/Tests/Typst.hs +++ b/tests/app/Spec/Tests/Typst.hs @@ -35,7 +35,7 @@ tests = describe [i|Typst|] $ introduceNixEnvironment [] config [i|Typst|] $ int void $ testBuild [i|exporters.typst.packageSearch|] describe "LSP" $ do - testDiagnosticsLabelDesired "simple" lsName "test.typ" (Just "typst") + testDiagnosticsLabelDesired "simple" lsName "test.typ" [__i|\#loremz(45)|] ((== [(Range (Position 0 1) (Position 0 7), Nothing, "unknown variable: loremz")]) . getDiagnosticRanges') diff --git a/tests/src/TestLib/LSP.hs b/tests/src/TestLib/LSP.hs index 3d4c6451..c314a30c 100644 --- a/tests/src/TestLib/LSP.hs +++ b/tests/src/TestLib/LSP.hs @@ -10,12 +10,10 @@ module TestLib.LSP ( , doNotebookSession , doSession' + , doSession'' - , withLspSession - , withLspSession' - - , getDiagnosticRanges - , getDiagnosticRanges' + , Helpers.getDiagnosticRanges + , Helpers.getDiagnosticRanges' , assertDiagnosticRanges , assertDiagnosticRanges' , testDiagnostics @@ -23,96 +21,40 @@ module TestLib.LSP ( , testDiagnosticsLabelDesired , testDiagnostics'' - , getHoverOrException - , allHoverText , itHasHoverSatisfying - , containsAll + , Helpers.getHoverOrException + , Helpers.allHoverText + , Helpers.containsAll , LspContext ) where -import Control.Applicative -import Control.Lens hiding (List) import Control.Monad -import Control.Monad.Catch as C (MonadCatch, MonadMask, MonadThrow) import Control.Monad.IO.Unlift -import Control.Monad.Logger (MonadLogger, MonadLoggerIO) +import Control.Monad.Logger (MonadLogger) import Control.Monad.Reader -import Control.Monad.Trans.Control (MonadBaseControl) import Data.Aeson as A -import Data.Aeson.TH as A import qualified Data.ByteString as B -import Data.Default -import Data.Function import qualified Data.List as L -import Data.Map (Map) -import qualified Data.Map as M import Data.Maybe -import qualified Data.Set as S import Data.String.Interpolate import qualified Data.Text as T hiding (filter) import Data.Text hiding (filter, show) -import qualified Data.Text.IO as T import GHC.Int import GHC.Stack -import Language.LSP.Protocol.Capabilities -import Language.LSP.Protocol.Lens as LSP hiding (diagnostics, hover, id, label, name, ranges) import Language.LSP.Protocol.Types import Language.LSP.Test +import Language.LSP.Test.Helpers (LanguageServerConfig(..), LspContext, LspSessionOptions(..), defaultLspSessionOptions, withLspSession) +import qualified Language.LSP.Test.Helpers as Helpers import System.FilePath -import System.IO.Temp (createTempDirectory) import Test.Sandwich as Sandwich -import Test.Sandwich.Waits (waitUntil) -import TestLib.Aeson import TestLib.Types -import UnliftIO.Async import UnliftIO.Directory import UnliftIO.Exception import UnliftIO.IO -import UnliftIO.IORef import UnliftIO.Process -import UnliftIO.STM - - -data LanguageServerType = LanguageServerTypeTcp - | LanguageServerTypeStream - deriving (Show, Eq) -deriveJSON toSnakeC3 ''LanguageServerType - -data LanguageServerConfig = LanguageServerConfig { - lspConfigName :: Text - , lspConfigVersion :: Maybe Text - , lspConfigDescription :: Maybe Text - , lspConfigDisplayName :: Maybe Text - , lspConfigIcon :: Maybe FilePath - , lspConfigExtensions :: [Text] - , lspConfigAttrs :: S.Set Text - , lspConfigType :: LanguageServerType - , lspConfigPrimary :: Maybe Bool - , lspConfigArgs :: [Text] - , lspConfigLanguageId :: Maybe Text - , lspConfigInitializationOptions :: Maybe A.Object - , lspConfigNotebookSuffix :: Text - , lspConfigKernelName :: Maybe Text - , lspConfigEnv :: Maybe (Map Text Text) - , lspConfigFile :: Maybe FilePath - , lspConfigIsBuiltIn :: Maybe Bool - } deriving (Show, Eq) -deriveJSON toSnake2 ''LanguageServerConfig - -type LspContext ctx m = ( - Alternative m - , MonadIO m - , MonadBaseControl IO m - , MonadUnliftIO m - , MonadCatch m - , MonadThrow m - , MonadMask m - - , HasBaseContext ctx - , HasMaybeBubblewrap ctx - ) + doNotebookSession :: ( LspContext ctx m, HasNixEnvironment ctx @@ -130,156 +72,90 @@ doSession'' :: ( doSession'' filename lsName codeToUse extraFiles cb = do lspConfig <- findLspConfig lsName (pathToUse, closure) <- getPathAndNixEnvironmentClosure - withLspSession lspConfig pathToUse closure (T.unpack filename) codeToUse extraFiles $ \_homeDir -> do + let lspSessionOptions = (defaultLspSessionOptions lspConfig) { + lspSessionOptionsInitialFileName = T.unpack filename + , lspSessionOptionsInitialCode = codeToUse + , lspSessionOptionsExtraFiles = extraFiles + , lspSessionOptionsReadOnlyBinds = closure + , lspSessionOptionsPathEnvVar = pathToUse + } + withLspSession lspSessionOptions $ \_homeDir -> do cb (T.unpack filename) testDiagnostics :: ( LspContext ctx m, HasNixEnvironment ctx - ) => Text -> FilePath -> Maybe LanguageKind -> Text -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () -testDiagnostics name filename maybeLanguageId codeToTest = testDiagnostics' name filename maybeLanguageId codeToTest [] + ) => Text -> FilePath -> Text -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () +testDiagnostics name filename code = testDiagnostics' name filename code [] testDiagnostics' :: ( LspContext ctx m, HasNixEnvironment ctx - ) => Text -> FilePath -> Maybe LanguageKind -> Text -> [(FilePath, B.ByteString)] -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () -testDiagnostics' name filename maybeLanguageId codeToTest = testDiagnostics'' [i|#{name}, #{filename} with #{show codeToTest} (diagnostics)|] name filename maybeLanguageId codeToTest + ) => Text -> FilePath -> Text -> [(FilePath, B.ByteString)] -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () +testDiagnostics' name filename codeToTest = testDiagnostics'' [i|#{name}, #{filename} with #{show codeToTest} (diagnostics)|] name filename codeToTest testDiagnosticsLabel :: ( LspContext ctx m, HasNixEnvironment ctx - ) => String -> Text -> FilePath -> Maybe LanguageKind -> Text -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () -testDiagnosticsLabel label name filename maybeLanguageId codeToTest = testDiagnostics'' label name filename maybeLanguageId codeToTest [] + ) => String -> Text -> FilePath -> Text -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () +testDiagnosticsLabel label name filename codeToTest = testDiagnostics'' label name filename codeToTest [] testDiagnosticsLabelDesired :: ( LspContext ctx m, HasNixEnvironment ctx - ) => String -> Text -> FilePath -> Maybe LanguageKind -> Text -> ([Diagnostic] -> Bool) -> SpecFree ctx m () -testDiagnosticsLabelDesired label name filename maybeLanguageId codeToTest cb = it label $ do + ) => String -> Text -> FilePath -> Text -> ([Diagnostic] -> Bool) -> SpecFree ctx m () +testDiagnosticsLabelDesired label name filename code cb = it label $ do lspConfig <- findLspConfig name (pathToUse, closure) <- getPathAndNixEnvironmentClosure - withLspSession' id lspConfig pathToUse closure filename codeToTest [] $ \_homeDir -> do - _ <- openDoc filename (fromMaybe (LanguageKind_Custom name) maybeLanguageId) + let lspSessionOptions = (defaultLspSessionOptions lspConfig) { + lspSessionOptionsInitialFileName = filename + , lspSessionOptionsInitialCode = code + , lspSessionOptionsReadOnlyBinds = closure + , lspSessionOptionsPathEnvVar = pathToUse + } - lastSeenDiagsVar <- newTVarIO mempty + Helpers.testDiagnostics lspSessionOptions $ \diags -> + if | cb diags -> return True + | otherwise -> expectationFailure [i|Got unexpected diagnostics: #{diags}|] - let watchDiagnostics = forever $ do - diags <- waitForDiagnostics - atomically $ writeTVar lastSeenDiagsVar diags - - withAsync watchDiagnostics $ \_ -> do - waitUntil 60.0 $ do - flip fix [] $ \loop lastValue -> - if | cb lastValue -> return () - | otherwise -> do - newDiags <- atomically $ do - x <- readTVar lastSeenDiagsVar - when (x == lastValue) retrySTM - return x - loop newDiags testDiagnostics'' :: ( LspContext ctx m, HasNixEnvironment ctx - ) => String -> Text -> FilePath -> Maybe LanguageKind -> Text -> [(FilePath, B.ByteString)] -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () -testDiagnostics'' label name filename maybeLanguageId codeToTest extraFiles cb = it label $ do + ) => String -> Text -> FilePath-> Text -> [(FilePath, B.ByteString)] -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () +testDiagnostics'' label name filename code extraFiles cb = it label $ do lspConfig <- findLspConfig name (pathToUse, closure) <- getPathAndNixEnvironmentClosure - withLspSession' id lspConfig pathToUse closure filename codeToTest extraFiles $ \_homeDir -> do - _ <- openDoc filename (fromMaybe (LanguageKind_Custom name) maybeLanguageId) + let lspSessionOptions = (defaultLspSessionOptions lspConfig) { + lspSessionOptionsInitialFileName = filename + , lspSessionOptionsInitialCode = code + , lspSessionOptionsReadOnlyBinds = closure + , lspSessionOptionsPathEnvVar = pathToUse + , lspSessionOptionsExtraFiles = extraFiles + } - lastSeenDiagsVar <- newIORef mempty + Helpers.testDiagnostics lspSessionOptions $ \diags -> do + lift $ cb diags + return True - waitUntil 60.0 $ do - diags <- waitForDiagnostics - writeIORef lastSeenDiagsVar diags - withException (lift $ cb diags) $ \(e :: SomeException) -> do - lastSeenDiags <- readIORef lastSeenDiagsVar - logError [i|Exception in testDiagnostics'': #{e}.\n\nLast seen diagnostics: #{A.encode lastSeenDiags}|] itHasHoverSatisfying :: ( LspContext ctx m, HasNixEnvironment ctx - ) => Text -> FilePath -> Maybe LanguageKind -> Text -> Position -> (Hover -> ExampleT ctx m ()) -> SpecFree ctx m () -itHasHoverSatisfying name filename maybeLanguageId codeToTest pos cb = it [i|#{name}: #{show codeToTest} (hover)|] $ do + ) => Text -> FilePath -> Text -> Position -> (Hover -> ExampleT ctx m ()) -> SpecFree ctx m () +itHasHoverSatisfying name filename code pos cb = it [i|#{name}: #{show code} (hover)|] $ do lspConfig <- findLspConfig name (pathToUse, closure) <- getPathAndNixEnvironmentClosure - withLspSession lspConfig pathToUse closure filename codeToTest [] $ \_homeDir -> do - ident <- openDoc filename (fromMaybe (LanguageKind_Custom name) maybeLanguageId) + let lspSessionOptions = (defaultLspSessionOptions lspConfig) { + lspSessionOptionsInitialFileName = filename + , lspSessionOptionsInitialCode = code + , lspSessionOptionsReadOnlyBinds = closure + , lspSessionOptionsPathEnvVar = pathToUse + } + + withLspSession lspSessionOptions $ \_ -> do + ident <- openDoc filename (fromMaybe (LanguageKind_Custom "unknown") (lspConfigLanguageId lspConfig)) getHover ident pos >>= \case Nothing -> expectationFailure [i|Expected a hover.|] Just x -> lift $ cb x -withLspSession :: ( - LspContext ctx m - ) => LanguageServerConfig -> FilePath -> [FilePath] -> FilePath -> Text -> [(FilePath, B.ByteString)] -> (FilePath -> Session (ExampleT ctx m) a) -> ExampleT ctx m a -withLspSession = withLspSession' handleSessionException - -handleSessionException :: MonadUnliftIO m => ExampleT ctx m a -> ExampleT ctx m a -handleSessionException = handle (\(e :: SessionException) -> expectationFailure [i|LSP session failed with SessionException: #{e}|]) - -withLspSession' :: ( - LspContext ctx m - ) => (ExampleT ctx m a -> ExampleT ctx m a) -> LanguageServerConfig -> FilePath -> [FilePath] -> FilePath -> Text -> [(FilePath, B.ByteString)] -> (FilePath -> Session (ExampleT ctx m) a) -> ExampleT ctx m a -withLspSession' handleFn config pathToUse fullClosure filename codeToTest extraFiles session = do - Just currentFolder <- getCurrentFolder - - homeDir <- liftIO $ createTempDirectory currentFolder "home" - - forM_ extraFiles $ \(path, bytes) -> do - unless (isAbsolute path) $ do - debug [i|Writing extra file: #{homeDir path}|] - createDirectoryIfMissing True (homeDir takeDirectory path) - liftIO $ B.writeFile (homeDir path) bytes - - createDirectoryIfMissing True (homeDir takeDirectory filename) - - -- Comment this and use openDoc' to simulate an unsaved document - liftIO $ T.writeFile (homeDir filename) codeToTest - - let sessionConfig = def { lspConfig = fromMaybe mempty (lspConfigInitializationOptions config) - , logStdErr = True - , logMessages = True - , messageTimeout = 120 - } - - let cmd:args = fmap T.unpack $ lspConfigArgs config - (cp, modifyCp) <- getContext maybeBubblewrap >>= \case - Nothing -> do - let configEnv = maybe mempty (fmap (bimap T.unpack T.unpack) . M.toList) (lspConfigEnv config) - let finalEnv = ("HOME", homeDir) : ("PATH", pathToUse) : configEnv - info [i|Language server environment: #{finalEnv}|] - let modifyCp cp = cp { env = Just finalEnv - , cwd = Just homeDir } - return (proc cmd args, modifyCp) - Just bwrapBinary -> do - let bwrapArgs = ["--tmpfs", "/tmp" - , "--bind", homeDir, homeDir - , "--clearenv" - , "--setenv", "HOME", homeDir - , "--chdir", homeDir - - , "--setenv", "PATH", pathToUse - - , "--proc", "/proc" - , "--dev", "/dev" - ] - <> mconcat [["--ro-bind", x, x] | x <- fullClosure] - <> mconcat [["--setenv", T.unpack n, T.unpack v] | (n, v) <- M.toList (fromMaybe mempty (lspConfigEnv config))] - <> ["--"] - <> (cmd : args) - - return (proc bwrapBinary bwrapArgs, id) - - info [i|LSP command: #{cp}|] - - -- We don't support certain server-to-client requests, since the waitForDiagnostics doesn't handle them - let caps = fullClientCapsForVersion (LSPVersion 3 16) - & set (workspace . _Just . workspaceFolders) Nothing - & set (workspace . _Just . configuration) Nothing - & set (workspace . _Just . didChangeWatchedFiles . _Just . dynamicRegistration) (Just False) - & set (workspace . _Just . didChangeConfiguration . _Just . dynamicRegistration) (Just False) - & set (textDocument . _Just . semanticTokens . _Just . dynamicRegistration) (Just False) - - handleFn $ runSessionWithConfigCustomProcess modifyCp sessionConfig cp caps homeDir (session homeDir) - findLspConfig :: ( MonadIO m, MonadLogger m, MonadReader context m, Sandwich.HasLabel context "nixEnvironment" FilePath ) => Text -> m LanguageServerConfig @@ -335,10 +211,7 @@ assertDiagnosticRanges diagnostics desired = if Found: #{A.encode found} |] where - found = getDiagnosticRanges diagnostics - -getDiagnosticRanges :: [Diagnostic] -> [(Range, Maybe (Int32 |? Text))] -getDiagnosticRanges = fmap (\x -> (x ^. range, x ^. code)) + found = Helpers.getDiagnosticRanges diagnostics assertDiagnosticRanges' :: (HasCallStack, MonadIO m) => [Diagnostic] -> [(Range, Maybe (Int32 |? Text), Text)] -> m () assertDiagnosticRanges' diagnostics desired = if @@ -351,34 +224,4 @@ assertDiagnosticRanges' diagnostics desired = if Found: #{A.encode found} |] where - found = getDiagnosticRanges' diagnostics - -getDiagnosticRanges' :: [Diagnostic] -> [(Range, Maybe (Int32 |? Text), Text)] -getDiagnosticRanges' = fmap (\x -> (x ^. range, x ^. code, x ^. LSP.message)) - --- hoverShouldSatisfy :: MonadThrow m => Position -> (Maybe Hover -> ExampleT ctx m ()) -> ExampleT ctx m () --- hoverShouldSatisfy pos pred = getHover (TextDocumentIdentifier (Uri undefined)) pos >>= pred - -getHoverOrException :: ( - MonadLoggerIO m, MonadThrow m, MonadUnliftIO m, Alternative m - ) => TextDocumentIdentifier -> Position -> Session m Hover -getHoverOrException tdi pos = getHover tdi pos >>= \case - Nothing -> expectationFailure [i|No hover returned.|] - Just x -> return x - -allHoverText :: Hover -> Text -allHoverText hover = allHoverContentsText (hover ^. contents) - -type HoverContents = MarkupContent |? (MarkedString |? [MarkedString]) - -allHoverContentsText :: HoverContents -> Text -allHoverContentsText (InL (MarkupContent _ t)) = t -allHoverContentsText (InR markedStrings) = case markedStrings of - InL ms -> markedStringToText ms - InR mss -> mconcat $ fmap markedStringToText mss - where - markedStringToText (MarkedString (InL t)) = t - markedStringToText (MarkedString (InR thing)) = thing ^. LSP.value - -containsAll :: Text -> [Text] -> Bool -containsAll haystack = Prelude.all (`T.isInfixOf` haystack) + found = Helpers.getDiagnosticRanges' diagnostics diff --git a/tests/stack.yaml b/tests/stack.yaml index 1b4dd057..df0651f1 100644 --- a/tests/stack.yaml +++ b/tests/stack.yaml @@ -3,6 +3,7 @@ resolver: nightly-2025-12-25 packages: - . +# - /home/tom/tools/lsp-test-helpers nix: enable: false @@ -18,6 +19,10 @@ extra-deps: - lsp-test - lsp-types +- git: https://github.com/codedownio/lsp-test-helpers.git + # main branch + commit: 10a74a28168b56428ab7c465d8e25e4d9e4e4734 + - ex-pool-0.2.1@sha256:c8249338ced27bc4d6395ad9c3069eec394fb111813d6ec736814d095f7e6a24,1293 - git: https://github.com/codedownio/minio-hs From 6848fdab9da1e8cceb806686836015c045e280a6 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Sun, 11 Jan 2026 18:03:32 -0800 Subject: [PATCH 2/5] Fill in language_id for LSP configs --- modules/kernels/bash/language_server_bash/default.nix | 1 + modules/kernels/clojure/language-server.nix | 1 + modules/kernels/cpp/language_server_clangd/default.nix | 1 + modules/kernels/go/language-server-gopls.nix | 1 + modules/kernels/haskell/language-server-hls/config.nix | 2 ++ .../python/language_servers/language_server_flake8/config.nix | 1 + .../python/language_servers/language_server_jedi/config.nix | 1 + .../language_servers/language_server_microsoft/config.nix | 1 + .../python/language_servers/language_server_palantir/config.nix | 1 + .../language_servers/language_server_pycodestyle/config.nix | 1 + .../python/language_servers/language_server_pylint/config.nix | 1 + .../python/language_servers/language_server_pyright/config.nix | 2 ++ .../language_servers/language_server_pythonlsp/config.nix | 1 + modules/kernels/r/language-server-languageserver/default.nix | 1 + modules/kernels/ruby/solargraph.nix | 1 + modules/kernels/rust/language_server_rust_analyzer/config.nix | 2 ++ 16 files changed, 19 insertions(+) diff --git a/modules/kernels/bash/language_server_bash/default.nix b/modules/kernels/bash/language_server_bash/default.nix index 02e94518..e59b301e 100644 --- a/modules/kernels/bash/language_server_bash/default.nix +++ b/modules/kernels/bash/language_server_bash/default.nix @@ -48,4 +48,5 @@ common.writeTextDirWithMetaAndPassthru bashLanguageServerWithMan.meta passthru " "${bashLanguageServerWithMan}/bin/bash-language-server" "start" ]; + language_id = "shellscript"; }]) diff --git a/modules/kernels/clojure/language-server.nix b/modules/kernels/clojure/language-server.nix index 5a9127de..f7821705 100644 --- a/modules/kernels/clojure/language-server.nix +++ b/modules/kernels/clojure/language-server.nix @@ -30,4 +30,5 @@ common.writeTextDirWithMetaAndPassthru clojure-lsp.meta passthru "lib/codedown/l type = "stream"; args = ["${clojure-lsp}/bin/clojure-lsp"]; env = {}; + language_id = "clojure"; }]) diff --git a/modules/kernels/cpp/language_server_clangd/default.nix b/modules/kernels/cpp/language_server_clangd/default.nix index d428a430..87c93d17 100644 --- a/modules/kernels/cpp/language_server_clangd/default.nix +++ b/modules/kernels/cpp/language_server_clangd/default.nix @@ -29,4 +29,5 @@ common.writeTextDirWithMetaAndPassthru clangd.meta passthru "lib/codedown/langua args = [ "${clangd}/bin/clangd" ]; + language_id = "cpp"; }]) diff --git a/modules/kernels/go/language-server-gopls.nix b/modules/kernels/go/language-server-gopls.nix index 6d87f58f..5ae18552 100644 --- a/modules/kernels/go/language-server-gopls.nix +++ b/modules/kernels/go/language-server-gopls.nix @@ -45,6 +45,7 @@ common.writeTextDirWithMetaAndPassthru gopls.meta passthru "lib/codedown/languag type = "stream"; args = ["${goplsWrapped}/bin/gopls"]; env = {}; + language_id = "go"; }]) diff --git a/modules/kernels/haskell/language-server-hls/config.nix b/modules/kernels/haskell/language-server-hls/config.nix index 7eb78056..188376d6 100644 --- a/modules/kernels/haskell/language-server-hls/config.nix +++ b/modules/kernels/haskell/language-server-hls/config.nix @@ -81,6 +81,8 @@ let # checkParents = "CheckOnSave"; }; }; + + language_id = "haskell"; }; in diff --git a/modules/kernels/python/language_servers/language_server_flake8/config.nix b/modules/kernels/python/language_servers/language_server_flake8/config.nix index b242a320..59a9f466 100644 --- a/modules/kernels/python/language_servers/language_server_flake8/config.nix +++ b/modules/kernels/python/language_servers/language_server_flake8/config.nix @@ -81,4 +81,5 @@ common.writeTextDirWithMetaAndPassthru python.pkgs.flake8.meta passthru "lib/cod formatters = {}; formatFiletypes = {}; }; + language_id = "python"; }]) diff --git a/modules/kernels/python/language_servers/language_server_jedi/config.nix b/modules/kernels/python/language_servers/language_server_jedi/config.nix index e406c540..52b2b97a 100644 --- a/modules/kernels/python/language_servers/language_server_jedi/config.nix +++ b/modules/kernels/python/language_servers/language_server_jedi/config.nix @@ -40,4 +40,5 @@ common.writeTextDirWithMetaAndPassthru jls.meta passthru "lib/codedown/language- "/home/user/.local/${pythonEnv.sitePackages}" ]; }; + language_id = "python"; }]) diff --git a/modules/kernels/python/language_servers/language_server_microsoft/config.nix b/modules/kernels/python/language_servers/language_server_microsoft/config.nix index 1abc0233..a33132a8 100644 --- a/modules/kernels/python/language_servers/language_server_microsoft/config.nix +++ b/modules/kernels/python/language_servers/language_server_microsoft/config.nix @@ -88,4 +88,5 @@ common.writeTextDirWithMetaAndPassthru python-language-server.meta passthru "lib initialization_options = overrideExisting initialization_options { # cacheFolderPath = "${cache}/cache"; }; + language_id = "python"; }]) diff --git a/modules/kernels/python/language_servers/language_server_palantir/config.nix b/modules/kernels/python/language_servers/language_server_palantir/config.nix index 864442fc..5ca16d71 100644 --- a/modules/kernels/python/language_servers/language_server_palantir/config.nix +++ b/modules/kernels/python/language_servers/language_server_palantir/config.nix @@ -61,4 +61,5 @@ common.writeTextDirWithMetaAndPassthru python.pkgs.python-language-server.meta p type = "stream"; args = ["${python}/bin/python" "-m" "pyls"]; initialization_options = import ../pylsp_initialization_options.nix "pyls"; + language_id = "python"; }]) diff --git a/modules/kernels/python/language_servers/language_server_pycodestyle/config.nix b/modules/kernels/python/language_servers/language_server_pycodestyle/config.nix index 0f5679d7..eaa21a81 100644 --- a/modules/kernels/python/language_servers/language_server_pycodestyle/config.nix +++ b/modules/kernels/python/language_servers/language_server_pycodestyle/config.nix @@ -80,4 +80,5 @@ common.writeTextDirWithMetaAndPassthru python.pkgs.pycodestyle.meta passthru "li formatters = {}; formatFiletypes = {}; }; + language_id = "python"; }]) diff --git a/modules/kernels/python/language_servers/language_server_pylint/config.nix b/modules/kernels/python/language_servers/language_server_pylint/config.nix index e4a1c304..802a2295 100644 --- a/modules/kernels/python/language_servers/language_server_pylint/config.nix +++ b/modules/kernels/python/language_servers/language_server_pylint/config.nix @@ -90,4 +90,5 @@ common.writeTextDirWithMetaAndPassthru python.pkgs.pylint.meta passthru "lib/cod formatters = {}; formatFiletypes = {}; }; + language_id = "python"; }]) diff --git a/modules/kernels/python/language_servers/language_server_pyright/config.nix b/modules/kernels/python/language_servers/language_server_pyright/config.nix index fea5420f..3f09c76f 100644 --- a/modules/kernels/python/language_servers/language_server_pyright/config.nix +++ b/modules/kernels/python/language_servers/language_server_pyright/config.nix @@ -64,4 +64,6 @@ common.writeTextDirWithMetaAndPassthru pyright.meta passthru "lib/codedown/langu # We need to send empty string, otherwise pyright-langserver fails with parse error # "python.venvPath" = ""; }; + + language_id = "python"; }]) diff --git a/modules/kernels/python/language_servers/language_server_pythonlsp/config.nix b/modules/kernels/python/language_servers/language_server_pythonlsp/config.nix index 25825dba..0b7bad18 100644 --- a/modules/kernels/python/language_servers/language_server_pythonlsp/config.nix +++ b/modules/kernels/python/language_servers/language_server_pythonlsp/config.nix @@ -62,4 +62,5 @@ common.writeTextDirWithMetaAndPassthru python.pkgs.python-lsp-server.meta passth type = "stream"; args = ["${python}/bin/python" "-m" "pylsp"]; initialization_options = import ../pylsp_initialization_options.nix "pylsp"; + language_id = "python"; }]) diff --git a/modules/kernels/r/language-server-languageserver/default.nix b/modules/kernels/r/language-server-languageserver/default.nix index 2424f2f0..0c7404eb 100644 --- a/modules/kernels/r/language-server-languageserver/default.nix +++ b/modules/kernels/r/language-server-languageserver/default.nix @@ -37,4 +37,5 @@ common.writeTextDirWithMetaAndPassthru languageserver.meta passthru "lib/codedow type = "stream"; primary = true; args = ["${rWithPackagesAndLanguageServer}/bin/R" "--slave" "-e" "languageserver::run()"]; + language_id = "r"; }]) diff --git a/modules/kernels/ruby/solargraph.nix b/modules/kernels/ruby/solargraph.nix index c5f80c4d..6e9972e6 100644 --- a/modules/kernels/ruby/solargraph.nix +++ b/modules/kernels/ruby/solargraph.nix @@ -30,4 +30,5 @@ common.writeTextDirWithMetaAndPassthru solargraph.meta passthru "lib/codedown/la attrs = ["ruby"]; type = "stream"; args = ["${solargraph}/bin/solargraph" "stdio"]; + language_id = "ruby"; }]) diff --git a/modules/kernels/rust/language_server_rust_analyzer/config.nix b/modules/kernels/rust/language_server_rust_analyzer/config.nix index 1d233a5d..575d1c97 100644 --- a/modules/kernels/rust/language_server_rust_analyzer/config.nix +++ b/modules/kernels/rust/language_server_rust_analyzer/config.nix @@ -174,6 +174,8 @@ let # "RA_LOG" = "rust_analyzer=info"; }; + + language_id = "rust"; }; in From afc2016621da6d878d00e5ff8469e5279669fa18 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Sun, 11 Jan 2026 18:04:45 -0800 Subject: [PATCH 3/5] More progress switching to lsp-test-helpers --- tests/app/Spec/Tests/Bash.hs | 2 +- tests/app/Spec/Tests/Clojure.hs | 2 +- tests/app/Spec/Tests/Cpp.hs | 2 +- tests/app/Spec/Tests/Go.hs | 2 +- tests/app/Spec/Tests/Haskell/CodeActions.hs | 9 +-- tests/app/Spec/Tests/Haskell/Diagnostics.hs | 12 ++-- .../Spec/Tests/Haskell/DocumentHighlight.hs | 9 +-- tests/app/Spec/Tests/Haskell/Hover.hs | 9 +-- tests/app/Spec/Tests/Haskell/Statements.hs | 13 ++-- tests/app/Spec/Tests/Haskell/Symbols.hs | 5 +- tests/app/Spec/Tests/Julia.hs | 7 +- tests/app/Spec/Tests/Julia/Diagnostics.hs | 8 +-- tests/app/Spec/Tests/Python.hs | 22 +++--- tests/app/Spec/Tests/Ruby.hs | 2 +- tests/app/Spec/Tests/Rust/Changes.hs | 5 +- tests/app/Spec/Tests/Rust/Completion.hs | 5 +- tests/app/Spec/Tests/Rust/Diagnostics.hs | 17 +++-- tests/app/Spec/Tests/Rust/Hovers.hs | 5 +- tests/app/Spec/Tests/Spellchecker.hs | 7 +- tests/app/Spec/Tests/Typst.hs | 2 +- tests/package.yaml | 5 +- tests/src/TestLib/LSP.hs | 72 ++++++++----------- tests/stack.yaml | 5 +- tests/stack.yaml.lock | 22 +++--- tests/tests.cabal | 6 +- 25 files changed, 123 insertions(+), 132 deletions(-) diff --git a/tests/app/Spec/Tests/Bash.hs b/tests/app/Spec/Tests/Bash.hs index 9b347d25..bea91966 100644 --- a/tests/app/Spec/Tests/Bash.hs +++ b/tests/app/Spec/Tests/Bash.hs @@ -37,7 +37,7 @@ tests = describe "Bash" $ introduceNixEnvironment [kernelSpec] [] "Bash" $ intro -- |] $ \diagnostics -> do -- assertDiagnosticRanges diagnostics [] - testDiagnostics "bash-language-server" "test.sh" [__i|FOO=42|] $ \diagnostics -> do + testDiagnostics "bash-language-server" "test.sh" LanguageKind_ShellScript [__i|FOO=42|] $ \diagnostics -> do assertDiagnosticRanges diagnostics [ (Range (Position 0 0) (Position 0 3), Just (InR "SC2034")) ] diff --git a/tests/app/Spec/Tests/Clojure.hs b/tests/app/Spec/Tests/Clojure.hs index 1a027d2b..c74cf848 100644 --- a/tests/app/Spec/Tests/Clojure.hs +++ b/tests/app/Spec/Tests/Clojure.hs @@ -31,7 +31,7 @@ tests = describe "Clojure" $ introduceNixEnvironment [kernelSpec] [] "Clojure" $ testKernelStdout "clojure" [__i|(println "hi")|] "hi\n" - testDiagnostics "clojure-lsp" "test.clj" [__i|(foo 42)|] $ \diagnostics -> do + testDiagnostics "clojure-lsp" "test.clj" LanguageKind_Clojure [__i|(foo 42)|] $ \diagnostics -> do assertDiagnosticRanges diagnostics [(Range (Position 0 1) (Position 0 4), Just (InR "unresolved-symbol"))] diff --git a/tests/app/Spec/Tests/Cpp.hs b/tests/app/Spec/Tests/Cpp.hs index 1120d69f..ff32492a 100644 --- a/tests/app/Spec/Tests/Cpp.hs +++ b/tests/app/Spec/Tests/Cpp.hs @@ -40,7 +40,7 @@ tests' flavor = describe [i|C++ (#{flavor})|] $ introduceNixEnvironment [kernelS testsWithLsp :: Text -> LanguageSpec testsWithLsp flavor = describe [i|C++ (#{flavor}) with LSP|] $ introduceNixEnvironment [kernelSpecWithLsp flavor] [] "C++" $ do describe "LSP" $ do - testDiagnostics'' "simple" lsName "test.cpp" + testDiagnostics'' "simple" lsName "test.cpp" LanguageKind_CPP [__i|int main() { undefined_function(); return 0; diff --git a/tests/app/Spec/Tests/Go.hs b/tests/app/Spec/Tests/Go.hs index 521b86d7..3ad5fcca 100644 --- a/tests/app/Spec/Tests/Go.hs +++ b/tests/app/Spec/Tests/Go.hs @@ -33,7 +33,7 @@ tests = describe "Go" $ introduceNixEnvironment [kernelSpec] [] "Go" $ introduce testKernelStdout "go" [__i|import("fmt") fmt.Println("hi")|] "hi\n" - testDiagnosticsLabel "gopls: Undeclared name" "gopls" "test.go" printUnknownCode $ \diagnostics -> + testDiagnosticsLabel "gopls: Undeclared name" "gopls" "test.go" LanguageKind_Go printUnknownCode $ \diagnostics -> assertDiagnosticRanges diagnostics [(Range (Position 3 12) (Position 3 15), Just (InR "UndeclaredName"))] printUnknownCode :: Text diff --git a/tests/app/Spec/Tests/Haskell/CodeActions.hs b/tests/app/Spec/Tests/Haskell/CodeActions.hs index a185a62e..4450695b 100644 --- a/tests/app/Spec/Tests/Haskell/CodeActions.hs +++ b/tests/app/Spec/Tests/Haskell/CodeActions.hs @@ -8,6 +8,7 @@ import Data.Text import Language.LSP.Protocol.Lens hiding (actions) import Language.LSP.Protocol.Types import Language.LSP.Test hiding (message) +import qualified Language.LSP.Test.Helpers as Helpers import Spec.Tests.Haskell.Common import Test.Sandwich as Sandwich import TestLib.LSP @@ -17,13 +18,13 @@ import UnliftIO.Timeout tests :: (LspContext context m, HasNixEnvironment context) => Text -> SpecFree context m () tests ghcPackage = describe "Code actions" $ do - it "gets no code actions for putStrLn" $ doNotebookSession lsName codeActionsCode $ \filename -> do - ident <- openDoc filename "haskell" + it "gets no code actions for putStrLn" $ doNotebookSession lsName codeActionsCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName "haskell" actions <- timeout 60_000_000 $ getCodeActions ident (Range (Position 1 0) (Position 1 8)) actions `shouldBe` (Just []) - it "gets code actions for foo" $ doNotebookSession lsName codeActionsCode $ \filename -> do - ident <- openDoc filename "haskell" + it "gets code actions for foo" $ doNotebookSession lsName codeActionsCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName "haskell" actions <- timeout 60_000_000 $ getCodeActions ident (Range (Position 0 0) (Position 0 3)) case ghcPackage of x | x `L.elem` ["ghc910", "ghc912"] -> actions `shouldBe` (Just []) -- TODO: figure out why this is diff --git a/tests/app/Spec/Tests/Haskell/Diagnostics.hs b/tests/app/Spec/Tests/Haskell/Diagnostics.hs index 26619d52..90870612 100644 --- a/tests/app/Spec/Tests/Haskell/Diagnostics.hs +++ b/tests/app/Spec/Tests/Haskell/Diagnostics.hs @@ -27,18 +27,18 @@ import TestLib.Types tests :: (LspContext context m, HasNixEnvironment context) => Text -> Text -> SpecFree context m () tests ghcPackage lsName = describe "Diagnostics" $ do describe "Foo.hs" $ do - testDiagnosticsLabelDesired "Out of scope variable" lsName "Foo.hs" + testDiagnosticsLabelDesired "Out of scope variable" lsName "Foo.hs" LanguageKind_Haskell [__i|module Foo where foo = bar |] ((== [(Range (Position 1 6) (Position 1 9), Just (InR "GHC-88464"))]) . getDiagnosticRanges) when (ghcPackage /= "ghc910") $ -- TODO: re-enable hlint test - testDiagnosticsLabelDesired "Eta reduce" lsName "Foo.hs" etaExpandCode + testDiagnosticsLabelDesired "Eta reduce" lsName "Foo.hs" LanguageKind_Haskell etaExpandCode ((== [(Range (Position 6 0) (Position 6 14), Just (InR "refact:Eta reduce"))]) . getDiagnosticRanges) describe "main.ipynb" $ do - testDiagnosticsLabelDesired "Top-level putStrLn" lsName "main.ipynb" + testDiagnosticsLabelDesired "Top-level putStrLn" lsName "main.ipynb" LanguageKind_Haskell [__i|-- A comment foo = bar @@ -46,7 +46,7 @@ tests ghcPackage lsName = describe "Diagnostics" $ do |] ((== [(Range (Position 1 6) (Position 1 9), Just (InR "GHC-88464"))]) . getDiagnosticRanges) - testDiagnosticsLabel "Top-level putStrLn with diagnostic" lsName "main.ipynb" + testDiagnosticsLabel "Top-level putStrLn with diagnostic" lsName "main.ipynb" LanguageKind_Haskell [__i|-- Some comment import Data.ByteString.Lazy.Char8 as BL foo = bar @@ -56,7 +56,7 @@ tests ghcPackage lsName = describe "Diagnostics" $ do [(Range (Position 4 0) (Position 4 8), x)] | containsAll x ["Ambiguous occurrence", "putStrLn"] -> return () xs -> expectationFailure [i|Unexpected diagnostics: #{xs}|] - testDiagnosticsLabelDesired "Reordering" lsName "main.ipynb" + testDiagnosticsLabelDesired "Reordering" lsName "main.ipynb" LanguageKind_Haskell [__i|import Data.Aeson.TH {-\# LANGUAGE TemplateHaskell \#-} foo = bar -- This should be the only diagnostic we get @@ -64,7 +64,7 @@ tests ghcPackage lsName = describe "Diagnostics" $ do $(deriveJSON defaultOptions ''Foo)|] ((== [(Range (Position 2 6) (Position 2 9), Just (InR "GHC-88464"))]) . getDiagnosticRanges) - testDiagnosticsLabelDesired "Complicated reordering" lsName "main.ipynb" + testDiagnosticsLabelDesired "Complicated reordering" lsName "main.ipynb" LanguageKind_Haskell [__i|import Data.Aeson as A import Data.Aeson.TH :set -XTemplateHaskell diff --git a/tests/app/Spec/Tests/Haskell/DocumentHighlight.hs b/tests/app/Spec/Tests/Haskell/DocumentHighlight.hs index 678e32fa..47bf0480 100644 --- a/tests/app/Spec/Tests/Haskell/DocumentHighlight.hs +++ b/tests/app/Spec/Tests/Haskell/DocumentHighlight.hs @@ -10,6 +10,7 @@ import Data.String.Interpolate import Data.Text as T import Language.LSP.Protocol.Types import Language.LSP.Test hiding (message) +import qualified Language.LSP.Test.Helpers as Helpers import Spec.Tests.Haskell.Common import Test.Sandwich as Sandwich import TestLib.LSP @@ -18,12 +19,12 @@ import TestLib.Types tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m () tests = describe "Document highlight" $ do - it "foo (.ipynb)" $ doNotebookSession lsName documentHighlightCode $ \filename -> do - ident <- openDoc filename "haskell" + it "foo (.ipynb)" $ doNotebookSession lsName documentHighlightCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName "haskell" getHighlights ident (Position 0 1) >>= (`shouldBe` documentHighlightResults) - it "foo (.hs)" $ doSession' "Test.hs" lsName documentHighlightCodeRegular $ \filename -> do - ident <- openDoc filename "haskell" + it "foo (.hs)" $ doSession' "Test.hs" lsName documentHighlightCodeRegular $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName "haskell" getHighlights ident (Position 0 1) >>= ( `shouldBe` [ DocumentHighlight (Range (Position 0 0) (Position 0 3)) (Just DocumentHighlightKind_Write) diff --git a/tests/app/Spec/Tests/Haskell/Hover.hs b/tests/app/Spec/Tests/Haskell/Hover.hs index 52e0bce4..848b4447 100644 --- a/tests/app/Spec/Tests/Haskell/Hover.hs +++ b/tests/app/Spec/Tests/Haskell/Hover.hs @@ -8,6 +8,7 @@ import Data.Text as T import Language.LSP.Protocol.Lens hiding (hover) import Language.LSP.Protocol.Types import Language.LSP.Test hiding (message) +import qualified Language.LSP.Test.Helpers as Helpers import Spec.Tests.Haskell.Common import Test.Sandwich as Sandwich import TestLib.LSP @@ -16,14 +17,14 @@ import TestLib.Types tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m () tests = describe "Hover" $ do - it "hovers foo" $ doNotebookSession lsName hoverCode $ \filename -> do - ident <- openDoc filename "haskell" + it "hovers foo" $ doNotebookSession lsName hoverCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName "haskell" hover <- getHoverOrException ident (Position 0 1) allHoverText hover `textShouldContain` [i|foo|] allHoverText hover `textShouldContain` [i|main.ipynb.hs:1:1|] - it "hovers putStrLn" $ doNotebookSession lsName hoverCode $ \filename -> do - ident <- openDoc filename "haskell" + it "hovers putStrLn" $ doNotebookSession lsName hoverCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName "haskell" hover <- getHoverOrException ident (Position 1 1) (hover ^. range) `shouldBe` Just (Range (Position 1 0) (Position 1 8)) let InL (MarkupContent {..}) = hover ^. contents diff --git a/tests/app/Spec/Tests/Haskell/Statements.hs b/tests/app/Spec/Tests/Haskell/Statements.hs index c75522e2..02419e7d 100644 --- a/tests/app/Spec/Tests/Haskell/Statements.hs +++ b/tests/app/Spec/Tests/Haskell/Statements.hs @@ -6,6 +6,7 @@ import Data.String.Interpolate import Data.Text as T import Language.LSP.Protocol.Types import Language.LSP.Test hiding (message) +import qualified Language.LSP.Test.Helpers as Helpers import Spec.Tests.Haskell.Common import Spec.Tests.Haskell.DocumentHighlight (documentHighlightResults) import Test.Sandwich as Sandwich @@ -17,23 +18,23 @@ import UnliftIO.Timeout tests :: (LspContext context m, HasNixEnvironment context) => Text -> SpecFree context m () tests ghcPackage = describe "Statements" $ do describe "Single-line" $ do - it "doesn't choke" $ doNotebookSession lsName statementsCode $ \filename -> do - ident <- openDoc filename "haskell" + it "doesn't choke" $ doNotebookSession lsName statementsCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName "haskell" timeout 120_000_000 (getHighlights ident (Position 0 1)) >>= (`shouldBe` (Just documentHighlightResults)) when (ghcPackage /= "ghc910") $ -- TODO: re-enable hlint test - testDiagnosticsLabel "Empty diagnostics" lsName "main.ipynb" statementsCode $ \diagnostics -> do + testDiagnosticsLabel "Empty diagnostics" lsName "main.ipynb" LanguageKind_Haskell statementsCode $ \diagnostics -> do -- Note: normally the server wouldn't send empty diagnostics. But the statement inserts "= unsafePerformIO $ ", -- which causes it to emit a "redundant bracket" diagnostic, which then gets filtered out by untransformPosition diagnostics `shouldBe` [] describe "Multi-line" $ do - it "doesn't choke" $ doNotebookSession lsName statementsCode $ \filename -> do - ident <- openDoc filename "haskell" + it "doesn't choke" $ doNotebookSession lsName statementsCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName "haskell" timeout 120_000_000 (getHighlights ident (Position 0 1)) >>= (`shouldBe` (Just documentHighlightResults)) when (ghcPackage /= "ghc910") $ -- TODO: re-enable hlint test - testDiagnosticsLabel "Redundant bracket" lsName "main.ipynb" statementsCodeMultiline $ \diagnostics -> do + testDiagnosticsLabel "Redundant bracket" lsName "main.ipynb" LanguageKind_Haskell statementsCodeMultiline $ \diagnostics -> do info [i|Got diagnostics: #{diagnostics}|] assertDiagnosticRanges diagnostics [(Range (Position 1 9) (Position 1 14), Just (InR "refact:Redundant bracket"))] diff --git a/tests/app/Spec/Tests/Haskell/Symbols.hs b/tests/app/Spec/Tests/Haskell/Symbols.hs index 495c2c38..27acdcc9 100644 --- a/tests/app/Spec/Tests/Haskell/Symbols.hs +++ b/tests/app/Spec/Tests/Haskell/Symbols.hs @@ -4,6 +4,7 @@ module Spec.Tests.Haskell.Symbols (tests) where import Control.Lens ((^.)) import Language.LSP.Protocol.Lens hiding (actions) import Language.LSP.Test hiding (message) +import qualified Language.LSP.Test.Helpers as Helpers import Spec.Tests.Haskell.Common import Spec.Tests.Haskell.DocumentHighlight (documentHighlightCode) import Test.Sandwich as Sandwich @@ -14,7 +15,7 @@ import UnliftIO.Timeout tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m () tests = describe "Symbols" $ do - it "symbols" $ doNotebookSession lsName documentHighlightCode $ \filename -> do - ident <- openDoc filename "haskell" + it "symbols" $ doNotebookSession lsName documentHighlightCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName "haskell" Just (Right documentSymbols) <- timeout 300_000_000 $ getDocumentSymbols ident fmap (^. name) documentSymbols `shouldBe` ["foo"] diff --git a/tests/app/Spec/Tests/Julia.hs b/tests/app/Spec/Tests/Julia.hs index a5b780c0..74486431 100644 --- a/tests/app/Spec/Tests/Julia.hs +++ b/tests/app/Spec/Tests/Julia.hs @@ -10,6 +10,7 @@ import Data.Text as T import Language.LSP.Protocol.Lens hiding (diagnostics, hover, text) import Language.LSP.Protocol.Types import Language.LSP.Test hiding (message) +import qualified Language.LSP.Test.Helpers as Helpers import Test.Sandwich as Sandwich import TestLib.JupyterRunnerContext import TestLib.LSP @@ -45,12 +46,12 @@ juliaTests juliaPackage = describe [i|Julia (#{juliaPackage})|] $ introduceNixEn describe "LSP" $ do Diagnostics.tests lsName - itHasHoverSatisfying lsName "test.jl" [__i|print("hi")|] (Position 0 2) $ \hover -> do + itHasHoverSatisfying lsName "test.jl" (LanguageKind_Custom "julia") [__i|print("hi")|] (Position 0 2) $ \hover -> do let InL (MarkupContent MarkupKind_Markdown text) = hover ^. contents text `textShouldContain` "Write to `io` (or to the default output stream" - it "highlights foo" $ doNotebookSession lsName documentHighlightCode $ \filename -> do - ident <- openDoc filename "julia" + it "highlights foo" $ doNotebookSession lsName documentHighlightCode $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName "julia" getHighlights ident (Position 0 1) >>= (`shouldBe` documentHighlightResults) diff --git a/tests/app/Spec/Tests/Julia/Diagnostics.hs b/tests/app/Spec/Tests/Julia/Diagnostics.hs index 60410eb8..d50df5da 100644 --- a/tests/app/Spec/Tests/Julia/Diagnostics.hs +++ b/tests/app/Spec/Tests/Julia/Diagnostics.hs @@ -13,10 +13,10 @@ import TestLib.Types tests :: (LspContext context m, HasNixEnvironment context) => Text -> SpecFree context m () tests lsName = describe "Diagnostics" $ do - testDiagnostics'' "flags a simple missing reference" lsName "test.jl" [i|printlnzzzz("HI")|] [] $ \diagnostics -> do + testDiagnostics'' "flags a simple missing reference" lsName "test.jl" (LanguageKind_Custom "julia") [i|printlnzzzz("HI")|] [] $ \diagnostics -> do assertDiagnosticRanges' diagnostics [(Range (Position 0 0) (Position 0 11), Nothing, "Missing reference: printlnzzzz")] - testDiagnosticsLabelDesired "finds symbols from JSON3 package" lsName "test.jl" + testDiagnosticsLabelDesired "finds symbols from JSON3 package" lsName "test.jl" (LanguageKind_Custom "julia") [__i|using JSON3: write tup = (:car,"Mercedes","S500",5,250.1) write(tup) @@ -24,7 +24,7 @@ tests lsName = describe "Diagnostics" $ do |] ((== [(Range (Position 3 0) (Position 3 11), Nothing, "Missing reference: printlnzzzz")]) . getDiagnosticRanges') - testDiagnosticsLabelDesired "finds symbols from Roots package" lsName "test.jl" + testDiagnosticsLabelDesired "finds symbols from Roots package" lsName "test.jl" (LanguageKind_Custom "julia") [__i|using Roots: Bisection, find_zero f(x) = exp(x) - x^4 find_zero(f, (8, 9), Bisection()) @@ -34,7 +34,7 @@ tests lsName = describe "Diagnostics" $ do -- This test is tricky because symbols like "plot" actually come from RecipesBase (or something), so -- it checks we're indexing such a transitive dependency. - testDiagnosticsLabelDesired "finds symbols from Plots package" lsName "test.jl" + testDiagnosticsLabelDesired "finds symbols from Plots package" lsName "test.jl" (LanguageKind_Custom "julia") [__i|using Plots: plot, plot! xx = range(0, 10, length=100) y = sin.(xx) diff --git a/tests/app/Spec/Tests/Python.hs b/tests/app/Spec/Tests/Python.hs index 66345543..5b15e8f6 100644 --- a/tests/app/Spec/Tests/Python.hs +++ b/tests/app/Spec/Tests/Python.hs @@ -35,21 +35,21 @@ tests' (kernelName, pythonPackage) = introduceNixEnvironment [kernelSpec kernelN testKernelStdout "python3" [i|print(42)|] "42\n" testKernelStdout' "python3" [i|import scipy|] Nothing - testDiagnostics "python-lsp-server" "test.py" [i|\n\n\nfoo = 42|] $ \diagnostics -> do + testDiagnostics "python-lsp-server" "test.py" LanguageKind_Python [i|\n\n\nfoo = 42|] $ \diagnostics -> do assertDiagnosticRanges diagnostics [] - testDiagnostics "pylint" "test.py" [i|\n\n\nfoo = 42|] $ \diagnostics -> do + testDiagnostics "pylint" "test.py" LanguageKind_Python [i|\n\n\nfoo = 42|] $ \diagnostics -> do assertDiagnosticRanges' diagnostics [ (Range (Position 3 0) (Position 3 0), Nothing, "Final newline missing (C0304:missing-final-newline)") , (Range (Position 0 0) (Position 0 0), Nothing, "Missing module docstring (C0114:missing-module-docstring)") , (Range (Position 3 0) (Position 3 0), Nothing, "Disallowed name \"foo\" (C0104:disallowed-name)") ] - testDiagnostics "pyright" "test.py" [__i|\# pyright: strict - def f(x: int, y: str) -> None: - z = 1.0 - f("asdf", 42) - |] $ \diagnostics -> do + testDiagnostics "pyright" "test.py" LanguageKind_Python [__i|\# pyright: strict + def f(x: int, y: str) -> None: + z = 1.0 + f("asdf", 42) + |] $ \diagnostics -> do assertDiagnosticRanges' diagnostics [ (Range (Position 3 2) (Position 3 8), Just (InR "reportArgumentType"), "Argument of type \"Literal['asdf']\" cannot be assigned to parameter \"x\" of type \"int\" in function \"f\"\n\160\160\"Literal['asdf']\" is not assignable to \"int\"") , (Range (Position 3 10) (Position 3 12), Just (InR "reportArgumentType"), "Argument of type \"Literal[42]\" cannot be assigned to parameter \"y\" of type \"str\" in function \"f\"\n\160\160\"Literal[42]\" is not assignable to \"str\"") @@ -61,10 +61,10 @@ tests' (kernelName, pythonPackage) = introduceNixEnvironment [kernelSpec kernelN , (Range (Position 2 2) (Position 2 3), Just (InR "reportUnusedVariable"), "Variable \"z\" is not accessed") ] - testDiagnostics "pycodestyle" "test.py" [__i|def f(x: int, y: str) -> None: - z = 1.0 - f("asdf", 42) - |] $ \diagnostics -> do + testDiagnostics "pycodestyle" "test.py" LanguageKind_Python [__i|def f(x: int, y: str) -> None: + z = 1.0 + f("asdf", 42) + |] $ \diagnostics -> do assertDiagnosticRanges diagnostics [] diff --git a/tests/app/Spec/Tests/Ruby.hs b/tests/app/Spec/Tests/Ruby.hs index af5f57f1..ec6dd56b 100644 --- a/tests/app/Spec/Tests/Ruby.hs +++ b/tests/app/Spec/Tests/Ruby.hs @@ -49,7 +49,7 @@ kernelTests rubyPackage = do info [i|RUBY_VERSION result: #{t}|] t `textShouldContain` versionString - itHasHoverSatisfying "solargraph" "test.rb" [__i|puts "hi"|] (Position 0 2) $ \hover -> do + itHasHoverSatisfying "solargraph" "test.rb" (LanguageKind_Ruby) [__i|puts "hi"|] (Position 0 2) $ \hover -> do let InL (MarkupContent MarkupKind_Markdown text) = hover ^. contents text `textShouldContain` "Kernel#puts" text `textShouldContain` "$stdout.puts(obj" diff --git a/tests/app/Spec/Tests/Rust/Changes.hs b/tests/app/Spec/Tests/Rust/Changes.hs index beccf27d..94fd253b 100644 --- a/tests/app/Spec/Tests/Rust/Changes.hs +++ b/tests/app/Spec/Tests/Rust/Changes.hs @@ -9,6 +9,7 @@ import Data.String.Interpolate import qualified Language.LSP.Protocol.Lens as LSP import Language.LSP.Protocol.Types import Language.LSP.Test +import qualified Language.LSP.Test.Helpers as Helpers import Test.Sandwich as Sandwich import Test.Sandwich.Waits (waitUntil) import TestLib.LSP @@ -17,8 +18,8 @@ import TestLib.Types tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m () tests = describe "Changes" $ do - it [i|Simple change|] $ doSession' "main.ipynb" "rust-analyzer" [i|println("hi");|] $ \filename -> do - ident <- openDoc filename "haskell" + it [i|Simple change|] $ doSession' "main.ipynb" "rust-analyzer" [i|println("hi");|] $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName "haskell" waitUntil 120.0 $ do waitForDiagnostics >>= \diags -> do diff --git a/tests/app/Spec/Tests/Rust/Completion.hs b/tests/app/Spec/Tests/Rust/Completion.hs index 93a483ef..da5c9eb9 100644 --- a/tests/app/Spec/Tests/Rust/Completion.hs +++ b/tests/app/Spec/Tests/Rust/Completion.hs @@ -7,6 +7,7 @@ import Data.String.Interpolate import Language.LSP.Protocol.Lens hiding (edit, item, range) import Language.LSP.Protocol.Types import Language.LSP.Test +import qualified Language.LSP.Test.Helpers as Helpers import Safe import Test.Sandwich as Sandwich import Test.Sandwich.Waits (waitUntil) @@ -17,8 +18,8 @@ import TestLib.Types tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m () tests = describe "Completions" $ do forM_ ["main.ipynb", "test.rs"] $ \doc -> do - it [i|(#{doc}) Completes printl to println!|] $ doSession' doc "rust-analyzer" [i|printl|] $ \filename -> do - ident <- openDoc filename "haskell" + it [i|(#{doc}) Completes printl to println!|] $ doSession' doc "rust-analyzer" [i|printl|] $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName "haskell" waitUntil 60 $ do completions <- getCompletions ident (Position 0 6) diff --git a/tests/app/Spec/Tests/Rust/Diagnostics.hs b/tests/app/Spec/Tests/Rust/Diagnostics.hs index 1fbc1150..36df9e16 100644 --- a/tests/app/Spec/Tests/Rust/Diagnostics.hs +++ b/tests/app/Spec/Tests/Rust/Diagnostics.hs @@ -14,16 +14,15 @@ import TestLib.Types tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m () tests = describe "Diagnostics" $ do - testDiagnostics "rust-analyzer" "main.ipynb" [__i|printlnz!("Hello world"); - |] $ \diagnostics -> do + testDiagnostics "rust-analyzer" "main.ipynb" LanguageKind_Rust [__i|printlnz!("Hello world");\n|] $ \diagnostics -> do assertDiagnosticRanges' diagnostics [ (Range (Position 0 0) (Position 0 8), Nothing, "cannot find macro `printlnz` in this scope") , (Range (Position 0 0) (Position 0 8), Nothing, "a macro with a similar name exists: `println`") ] - testDiagnostics "rust-analyzer" "test.rs" [__i|struct A { a: u8, b: u8 } - const a: A = A { a: 10, }; - |] $ \diagnostics -> do + testDiagnostics "rust-analyzer" "test.rs" LanguageKind_Rust [__i|struct A { a: u8, b: u8 } + const a: A = A { a: 10, }; + |] $ \diagnostics -> do assertDiagnosticRanges' (L.sortBy (compare `on` (^. LSP.message)) diagnostics) [ (Range (Position 1 13) (Position 1 14), Just (InR "E0063"), "missing field `b` in initializer of `A`\nmissing `b`") -- (Range (Position 1 6) (Position 1 7), Just (InR "non_upper_case_globals"), "Constant `a` should have UPPER_SNAKE_CASE name, e.g. `A`") @@ -31,10 +30,10 @@ tests = describe "Diagnostics" $ do -- , (Range (Position 1 13) (Position 1 14), Just (InR "E0063"), "missing structure fields:\n- b\n") ] - testDiagnostics "rust-analyzer" "main.ipynb" [__i|println!("Hello world"); - eprintln!("Hello error"); - format!("Hello {}", "world") - |] $ \diagnostics -> do + testDiagnostics "rust-analyzer" "main.ipynb" LanguageKind_Rust [__i|println!("Hello world"); + eprintln!("Hello error"); + format!("Hello {}", "world") + |] $ \diagnostics -> do assertDiagnosticRanges' (L.sortBy (compare `on` (^. LSP.message)) diagnostics) [ (Range (Position 2 0) (Position 2 28), Just (InR "E0308"), "mismatched types\nexpected `()`, found `String`") ] diff --git a/tests/app/Spec/Tests/Rust/Hovers.hs b/tests/app/Spec/Tests/Rust/Hovers.hs index 3bc5d2e2..b9ef13d5 100644 --- a/tests/app/Spec/Tests/Rust/Hovers.hs +++ b/tests/app/Spec/Tests/Rust/Hovers.hs @@ -6,6 +6,7 @@ import Control.Monad.IO.Unlift import Data.String.Interpolate import Language.LSP.Protocol.Types import Language.LSP.Test +import qualified Language.LSP.Test.Helpers as Helpers import Test.Sandwich as Sandwich import Test.Sandwich.Waits (waitUntil) import TestLib.LSP @@ -16,8 +17,8 @@ import UnliftIO.Exception tests :: (LspContext context m, HasNixEnvironment context) => SpecFree context m () tests = describe "Hovers" $ do forM_ ["main.ipynb", "test.rs"] $ \doc -> do - it [i|hovers println! (#{doc})|] $ doSession' doc "rust-analyzer" [i|println!("hi")|] $ \filename -> do - ident <- openDoc filename "haskell" + it [i|hovers println! (#{doc})|] $ doSession' doc "rust-analyzer" [i|println!("hi")|] $ \(Helpers.LspSessionInfo {..}) -> do + ident <- openDoc lspSessionInfoFileName "haskell" waitUntil 60 $ handle handleSessionException' $ do diff --git a/tests/app/Spec/Tests/Spellchecker.hs b/tests/app/Spec/Tests/Spellchecker.hs index 034a836b..92a3db50 100644 --- a/tests/app/Spec/Tests/Spellchecker.hs +++ b/tests/app/Spec/Tests/Spellchecker.hs @@ -11,6 +11,7 @@ import Data.Text.IO as T import Language.LSP.Protocol.Lens hiding (actions, diagnostics, executeCommand, id) import Language.LSP.Protocol.Types import Language.LSP.Test hiding (message) +import qualified Language.LSP.Test.Helpers as Helpers import Safe import System.FilePath import Test.Sandwich as Sandwich @@ -29,7 +30,7 @@ otherConfig = [ tests :: TopSpec tests = describe "Spellchecker" $ introduceNixEnvironment [] otherConfig "Spellchecker env" $ introduceJustBubblewrap $ do it "Gets diagnostics and a working code action" $ do - doSession'' "test.md" "spellchecker" [i|\# This is mispelled|] [] $ \lspHomeDir -> do + doSession'' "test.md" "spellchecker" [i|\# This is mispelled|] [] $ \(Helpers.LspSessionInfo {..}) -> do ident <- openDoc "test.md" "spellchecker" waitUntil 300.0 $ do diagnostics <- waitForDiagnostics @@ -44,7 +45,7 @@ tests = describe "Spellchecker" $ introduceNixEnvironment [] otherConfig "Spellc Just (InR ca) -> executeCodeAction ca waitUntil 30 $ do - let datPath = lspHomeDir ".codedown/personal-dictionary.dat" + let datPath = lspSessionInfoHomeDir ".codedown/personal-dictionary.dat" doesFileExist datPath >>= (`shouldBe` True) liftIO (T.readFile datPath) >>= (`shouldBe` "mispelled\n") @@ -56,7 +57,7 @@ tests = describe "Spellchecker" $ introduceNixEnvironment [] otherConfig "Spellc diagnostics <- waitForDiagnostics lift $ assertDiagnosticRanges diagnostics [] - testDiagnostics "spellchecker" "test.md" [i|I've done a thing.|] $ \diagnostics -> do + testDiagnostics "spellchecker" "test.md" LanguageKind_Markdown [i|I've done a thing.|] $ \diagnostics -> do assertDiagnosticRanges diagnostics [] diff --git a/tests/app/Spec/Tests/Typst.hs b/tests/app/Spec/Tests/Typst.hs index 2f4ebfad..2d41ae3b 100644 --- a/tests/app/Spec/Tests/Typst.hs +++ b/tests/app/Spec/Tests/Typst.hs @@ -35,7 +35,7 @@ tests = describe [i|Typst|] $ introduceNixEnvironment [] config [i|Typst|] $ int void $ testBuild [i|exporters.typst.packageSearch|] describe "LSP" $ do - testDiagnosticsLabelDesired "simple" lsName "test.typ" + testDiagnosticsLabelDesired "simple" lsName "test.typ" (LanguageKind_Custom "typst") [__i|\#loremz(45)|] ((== [(Range (Position 0 1) (Position 0 7), Nothing, "unknown variable: loremz")]) . getDiagnosticRanges') diff --git a/tests/package.yaml b/tests/package.yaml index be4f2100..792e7486 100644 --- a/tests/package.yaml +++ b/tests/package.yaml @@ -36,6 +36,7 @@ dependencies: - filepath - lens - lsp-test +- lsp-test-helpers - lsp-types - monad-control - mtl @@ -55,13 +56,10 @@ library: - bytestring - conduit - conduit-aeson - - data-default - directory - monad-logger - postgresql-simple - - row-types - template-haskell - - temporary - unliftio - unliftio-core - uri-encode @@ -77,7 +75,6 @@ executables: build-tools: sandwich:sandwich-discover dependencies: - monad-logger - - row-types - tests - unliftio - unliftio-core diff --git a/tests/src/TestLib/LSP.hs b/tests/src/TestLib/LSP.hs index c314a30c..5ec063eb 100644 --- a/tests/src/TestLib/LSP.hs +++ b/tests/src/TestLib/LSP.hs @@ -37,7 +37,6 @@ import Control.Monad.Reader import Data.Aeson as A import qualified Data.ByteString as B import qualified Data.List as L -import Data.Maybe import Data.String.Interpolate import qualified Data.Text as T hiding (filter) import Data.Text hiding (filter, show) @@ -58,100 +57,100 @@ import UnliftIO.Process doNotebookSession :: ( LspContext ctx m, HasNixEnvironment ctx - ) => Text -> Text -> (FilePath -> Session (ExampleT ctx m) a) -> ExampleT ctx m a + ) => Text -> Text -> (Helpers.LspSessionInfo -> Session (ExampleT ctx m) a) -> ExampleT ctx m a doNotebookSession = doSession' "main.ipynb" doSession' :: ( LspContext ctx m, HasNixEnvironment ctx - ) => Text -> Text -> Text -> (FilePath -> Session (ExampleT ctx m) a) -> ExampleT ctx m a + ) => Text -> Text -> Text -> (Helpers.LspSessionInfo -> Session (ExampleT ctx m) a) -> ExampleT ctx m a doSession' filename lsName codeToUse cb = doSession'' filename lsName codeToUse [] cb doSession'' :: ( LspContext ctx m, HasNixEnvironment ctx - ) => Text -> Text -> Text -> [(FilePath, B.ByteString)] -> (FilePath -> Session (ExampleT ctx m) a) -> ExampleT ctx m a + ) => Text -> Text -> Text -> [(FilePath, B.ByteString)] -> (Helpers.LspSessionInfo -> Session (ExampleT ctx m) a) -> ExampleT ctx m a doSession'' filename lsName codeToUse extraFiles cb = do lspConfig <- findLspConfig lsName (pathToUse, closure) <- getPathAndNixEnvironmentClosure let lspSessionOptions = (defaultLspSessionOptions lspConfig) { lspSessionOptionsInitialFileName = T.unpack filename + , lspSessionOptionsInitialLanguageKind = LanguageKind_Python , lspSessionOptionsInitialCode = codeToUse , lspSessionOptionsExtraFiles = extraFiles , lspSessionOptionsReadOnlyBinds = closure , lspSessionOptionsPathEnvVar = pathToUse } - withLspSession lspSessionOptions $ \_homeDir -> do - cb (T.unpack filename) + withLspSession lspSessionOptions cb testDiagnostics :: ( LspContext ctx m, HasNixEnvironment ctx - ) => Text -> FilePath -> Text -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () -testDiagnostics name filename code = testDiagnostics' name filename code [] + ) => Text -> FilePath -> LanguageKind -> Text -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () +testDiagnostics name filename languageKind code = testDiagnostics' name filename languageKind code [] testDiagnostics' :: ( LspContext ctx m, HasNixEnvironment ctx - ) => Text -> FilePath -> Text -> [(FilePath, B.ByteString)] -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () -testDiagnostics' name filename codeToTest = testDiagnostics'' [i|#{name}, #{filename} with #{show codeToTest} (diagnostics)|] name filename codeToTest + ) => Text -> FilePath -> LanguageKind -> Text -> [(FilePath, B.ByteString)] -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () +testDiagnostics' name filename languageKind codeToTest = testDiagnostics'' [i|#{name}, #{filename} with #{show codeToTest} (diagnostics)|] name filename languageKind codeToTest testDiagnosticsLabel :: ( LspContext ctx m, HasNixEnvironment ctx - ) => String -> Text -> FilePath -> Text -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () -testDiagnosticsLabel label name filename codeToTest = testDiagnostics'' label name filename codeToTest [] + ) => String -> Text -> FilePath -> LanguageKind -> Text -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () +testDiagnosticsLabel label name filename languageKind codeToTest = testDiagnostics'' label name filename languageKind codeToTest [] testDiagnosticsLabelDesired :: ( LspContext ctx m, HasNixEnvironment ctx - ) => String -> Text -> FilePath -> Text -> ([Diagnostic] -> Bool) -> SpecFree ctx m () -testDiagnosticsLabelDesired label name filename code cb = it label $ do + ) => String -> Text -> FilePath -> LanguageKind -> Text -> ([Diagnostic] -> Bool) -> SpecFree ctx m () +testDiagnosticsLabelDesired label name filename languageKind code cb = it label $ do lspConfig <- findLspConfig name (pathToUse, closure) <- getPathAndNixEnvironmentClosure let lspSessionOptions = (defaultLspSessionOptions lspConfig) { lspSessionOptionsInitialFileName = filename + , lspSessionOptionsInitialLanguageKind = languageKind , lspSessionOptionsInitialCode = code , lspSessionOptionsReadOnlyBinds = closure , lspSessionOptionsPathEnvVar = pathToUse } - Helpers.testDiagnostics lspSessionOptions $ \diags -> - if | cb diags -> return True + Helpers.testDiagnostics lspSessionOptions languageKind $ \diags -> + if | cb diags -> return () | otherwise -> expectationFailure [i|Got unexpected diagnostics: #{diags}|] - testDiagnostics'' :: ( LspContext ctx m, HasNixEnvironment ctx - ) => String -> Text -> FilePath-> Text -> [(FilePath, B.ByteString)] -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () -testDiagnostics'' label name filename code extraFiles cb = it label $ do + ) => String -> Text -> FilePath -> LanguageKind -> Text -> [(FilePath, B.ByteString)] -> ([Diagnostic] -> ExampleT ctx m ()) -> SpecFree ctx m () +testDiagnostics'' label name filename languageKind code extraFiles cb = it label $ do lspConfig <- findLspConfig name (pathToUse, closure) <- getPathAndNixEnvironmentClosure let lspSessionOptions = (defaultLspSessionOptions lspConfig) { lspSessionOptionsInitialFileName = filename + , lspSessionOptionsInitialLanguageKind = languageKind , lspSessionOptionsInitialCode = code , lspSessionOptionsReadOnlyBinds = closure , lspSessionOptionsPathEnvVar = pathToUse , lspSessionOptionsExtraFiles = extraFiles } - Helpers.testDiagnostics lspSessionOptions $ \diags -> do + Helpers.testDiagnostics lspSessionOptions languageKind $ \diags -> do lift $ cb diags - return True - itHasHoverSatisfying :: ( LspContext ctx m, HasNixEnvironment ctx - ) => Text -> FilePath -> Text -> Position -> (Hover -> ExampleT ctx m ()) -> SpecFree ctx m () -itHasHoverSatisfying name filename code pos cb = it [i|#{name}: #{show code} (hover)|] $ do + ) => Text -> FilePath -> LanguageKind -> Text -> Position -> (Hover -> ExampleT ctx m ()) -> SpecFree ctx m () +itHasHoverSatisfying name filename languageKind code pos cb = it [i|#{name}: #{show code} (hover)|] $ do lspConfig <- findLspConfig name (pathToUse, closure) <- getPathAndNixEnvironmentClosure let lspSessionOptions = (defaultLspSessionOptions lspConfig) { lspSessionOptionsInitialFileName = filename + , lspSessionOptionsInitialLanguageKind = languageKind , lspSessionOptionsInitialCode = code , lspSessionOptionsReadOnlyBinds = closure , lspSessionOptionsPathEnvVar = pathToUse } withLspSession lspSessionOptions $ \_ -> do - ident <- openDoc filename (fromMaybe (LanguageKind_Custom "unknown") (lspConfigLanguageId lspConfig)) + ident <- openDoc filename languageKind getHover ident pos >>= \case Nothing -> expectationFailure [i|Expected a hover.|] Just x -> lift $ cb x @@ -201,27 +200,18 @@ getPathAndNixEnvironmentClosure = do return (pathToUse, closure) assertDiagnosticRanges :: (HasCallStack, MonadIO m) => [Diagnostic] -> [(Range, Maybe (Int32 |? Text))] -> ExampleT ctx m () -assertDiagnosticRanges diagnostics desired = if - | found == desired -> return () - | otherwise -> - expectationFailure [__i|Got wrong diagnostics! - - Expected: #{A.encode desired} - - Found: #{A.encode found} - |] - where - found = Helpers.getDiagnosticRanges diagnostics +assertDiagnosticRanges = assertDiagnosticRanges'' Helpers.getDiagnosticRanges assertDiagnosticRanges' :: (HasCallStack, MonadIO m) => [Diagnostic] -> [(Range, Maybe (Int32 |? Text), Text)] -> m () -assertDiagnosticRanges' diagnostics desired = if - | found == desired -> return () +assertDiagnosticRanges' = assertDiagnosticRanges'' Helpers.getDiagnosticRanges' + +assertDiagnosticRanges'' :: (HasCallStack, MonadIO m, Eq a, ToJSON a) => ([Diagnostic] -> [a]) -> [Diagnostic] -> [a] -> m () +assertDiagnosticRanges'' keyFn diagnostics desired = if + | keyFn diagnostics == desired -> return () | otherwise -> expectationFailure [__i|Got wrong diagnostics! Expected: #{A.encode desired} - Found: #{A.encode found} + Found: #{A.encode $ keyFn diagnostics} |] - where - found = Helpers.getDiagnosticRanges' diagnostics diff --git a/tests/stack.yaml b/tests/stack.yaml index df0651f1..5f4160e9 100644 --- a/tests/stack.yaml +++ b/tests/stack.yaml @@ -21,9 +21,6 @@ extra-deps: - git: https://github.com/codedownio/lsp-test-helpers.git # main branch - commit: 10a74a28168b56428ab7c465d8e25e4d9e4e4734 + commit: 6a73e2393a1d9f21719580ce9ca0efbefabda60f - ex-pool-0.2.1@sha256:c8249338ced27bc4d6395ad9c3069eec394fb111813d6ec736814d095f7e6a24,1293 - -- git: https://github.com/codedownio/minio-hs - commit: 768665c90321d118fdd3cde2c6ac6c01310d76a0 diff --git a/tests/stack.yaml.lock b/tests/stack.yaml.lock index 6ccde934..c7f5cda9 100644 --- a/tests/stack.yaml.lock +++ b/tests/stack.yaml.lock @@ -43,6 +43,17 @@ packages: commit: d920b28aa25d454812d8d9bbd922e893574d45bc git: https://github.com/codedownio/lsp.git subdir: lsp-types +- completed: + commit: 6a73e2393a1d9f21719580ce9ca0efbefabda60f + git: https://github.com/codedownio/lsp-test-helpers.git + name: lsp-test-helpers + pantry-tree: + sha256: d13e5237e21a6896422743aeee3f46019ca022e3e7d51b3b7196b9db9ec956c8 + size: 1025 + version: 0.1.0.0 + original: + commit: 6a73e2393a1d9f21719580ce9ca0efbefabda60f + git: https://github.com/codedownio/lsp-test-helpers.git - completed: hackage: ex-pool-0.2.1@sha256:c8249338ced27bc4d6395ad9c3069eec394fb111813d6ec736814d095f7e6a24,1293 pantry-tree: @@ -50,17 +61,6 @@ packages: size: 253 original: hackage: ex-pool-0.2.1@sha256:c8249338ced27bc4d6395ad9c3069eec394fb111813d6ec736814d095f7e6a24,1293 -- completed: - commit: 768665c90321d118fdd3cde2c6ac6c01310d76a0 - git: https://github.com/codedownio/minio-hs - name: minio-hs - pantry-tree: - sha256: 63fecbf5146f8704eba62c12ba86494f7bc477d8d882e74846ea0d1dfce03a1a - size: 4744 - version: 1.7.0 - original: - commit: 768665c90321d118fdd3cde2c6ac6c01310d76a0 - git: https://github.com/codedownio/minio-hs snapshots: - completed: sha256: 671a94f04c2cb37457b71c66134242d4b12ab703597c19fad769df2d5e1e5659 diff --git a/tests/tests.cabal b/tests/tests.cabal index 94f408fe..6a155a39 100644 --- a/tests/tests.cabal +++ b/tests/tests.cabal @@ -59,25 +59,23 @@ library , conduit , conduit-aeson , containers - , data-default , directory , exceptions , filepath , lens , lsp-test + , lsp-test-helpers , lsp-types , monad-control , monad-logger , mtl , optparse-applicative , postgresql-simple - , row-types , safe , sandwich , sandwich-contexts , string-interpolate , template-haskell - , temporary , text , unliftio , unliftio-core @@ -150,12 +148,12 @@ executable tests , filepath , lens , lsp-test + , lsp-test-helpers , lsp-types , monad-control , monad-logger , mtl , optparse-applicative - , row-types , safe , sandwich , sandwich-contexts From ef973ee99874ad6338e4151995c7af2544c736bf Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Sun, 11 Jan 2026 18:06:07 -0800 Subject: [PATCH 4/5] Rename basic-path --- tests/flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/flake.nix b/tests/flake.nix index c42c2576..ea7d869e 100644 --- a/tests/flake.nix +++ b/tests/flake.nix @@ -34,7 +34,7 @@ # Print a trivial PATH that we can use to run kernel and LSP tests, to ensure # they aren't depending on anything on the test machine's PATH. - print-basic-path = pkgs.writeShellScriptBin "codedown-artifact-sizes.sh" '' + print-basic-path = pkgs.writeShellScriptBin "basic-path.sh" '' echo ${pkgs.lib.makeBinPath (with pkgs; [coreutils bash])} ''; From 35c568b12cddcc39362eea4e4c58cb76151c0ef0 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Tue, 13 Jan 2026 16:41:46 -0800 Subject: [PATCH 5/5] ci: don't run on PR --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cd35e2c1..6c32b844 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,6 @@ name: codedown-languages on: - pull_request: push: workflow_dispatch: