haskell-language-server 1.0.0.0 → 1.1.0.0
raw patch · 184 files changed
+7833/−7609 lines, 184 filesdep +aeson-prettydep +hls-brittany-plugindep +hls-stylish-haskell-plugindep −blaze-markupdep −brittanydep −hspecdep ~ghcidedep ~hls-class-plugindep ~hls-eval-pluginsetup-changednew-uploaderPVP ok
version bump matches the API change (PVP)
Dependencies added: aeson-pretty, hls-brittany-plugin, hls-stylish-haskell-plugin, hls-test-utils, lsp-types
Dependencies removed: blaze-markup, brittany, hspec, hspec-core, megaparsec, stm, stylish-haskell, tasty, tasty-ant-xml, tasty-expected-failure, tasty-golden, tasty-hunit, tasty-rerun, with-utf8, yaml
Dependency ranges changed: ghcide, hls-class-plugin, hls-eval-plugin, hls-explicit-imports-plugin, hls-haddock-comments-plugin, hls-hlint-plugin, hls-plugin-api, hls-retrie-plugin, hls-splice-plugin, hls-tactics-plugin, lsp-test, shake
API changes (from Hackage documentation)
Files
- ChangeLog.md +1333/−1048
- LICENSE +201/−201
- README.md +816/−767
- Setup.hs +2/−2
- exe/Main.hs +21/−22
- exe/Plugins.hs +143/−142
- exe/Wrapper.hs +151/−151
- haskell-language-server.cabal +48/−94
- include/ghc-api-version.h +10/−10
- plugins/default/src/Ide/Plugin/Brittany.hs +0/−118
- plugins/default/src/Ide/Plugin/Example.hs +236/−234
- plugins/default/src/Ide/Plugin/Example2.hs +229/−228
- plugins/default/src/Ide/Plugin/Floskell.hs +59/−59
- plugins/default/src/Ide/Plugin/Fourmolu.hs +103/−103
- plugins/default/src/Ide/Plugin/ModuleName.hs +157/−178
- plugins/default/src/Ide/Plugin/Ormolu.hs +80/−80
- plugins/default/src/Ide/Plugin/Pragmas.hs +191/−189
- plugins/default/src/Ide/Plugin/StylishHaskell.hs +0/−82
- plugins/hls-eval-plugin/src/Ide/Plugin/Eval/Types.hs +0/−162
- plugins/hls-eval-plugin/test/Eval.hs +0/−229
- plugins/hls-splice-plugin/src/Ide/Plugin/Splice/Types.hs +0/−54
- src/Ide/Arguments.hs +141/−130
- src/Ide/Main.hs +102/−106
- src/Ide/Version.hs +79/−79
- test/functional/Class.hs +0/−82
- test/functional/Command.hs +31/−34
- test/functional/Completion.hs +404/−410
- test/functional/Config.hs +96/−101
- test/functional/Deferred.hs +170/−176
- test/functional/Definition.hs +64/−69
- test/functional/Diagnostic.hs +76/−82
- test/functional/Format.hs +128/−185
- test/functional/FunctionalBadProject.hs +38/−40
- test/functional/FunctionalCodeAction.hs +700/−678
- test/functional/FunctionalLiquid.hs +31/−37
- test/functional/HaddockComments.hs +0/−79
- test/functional/HieBios.hs +33/−35
- test/functional/Highlight.hs +22/−26
- test/functional/Main.hs +45/−63
- test/functional/ModuleName.hs +36/−44
- test/functional/Progress.hs +113/−120
- test/functional/Reference.hs +31/−36
- test/functional/Rename.hs +23/−28
- test/functional/Splice.hs +0/−134
- test/functional/Symbol.hs +153/−157
- test/functional/TypeDefinition.hs +43/−47
- test/testdata/CodeActionImport.hs +2/−0
- test/testdata/CodeActionOnly.hs +3/−0
- test/testdata/CodeActionRename.hs +2/−0
- test/testdata/FuncTest.hs +13/−0
- test/testdata/FuncTestError.hs +15/−0
- test/testdata/FuncTestFail.hs +2/−0
- test/testdata/Highlight.hs +5/−0
- test/testdata/Hover.hs +2/−0
- test/testdata/References.hs +9/−0
- test/testdata/Symbols.hs +14/−0
- test/testdata/TopLevelSignature.hs +5/−0
- test/testdata/TypedHoles.hs +3/−0
- test/testdata/TypedHoles2.hs +6/−0
- test/testdata/UnusedTerm.hs +6/−0
- test/testdata/addPackageTest/cabal-exe/AddPackage.hs +3/−0
- test/testdata/addPackageTest/cabal-exe/add-package-test.cabal +14/−0
- test/testdata/addPackageTest/cabal-lib/AddPackage.hs +4/−0
- test/testdata/addPackageTest/cabal-lib/add-package-test.cabal +14/−0
- test/testdata/addPackageTest/hpack-exe/app/Asdf.hs +5/−0
- test/testdata/addPackageTest/hpack-exe/asdf.cabal +37/−0
- test/testdata/addPackageTest/hpack-lib/app/Asdf.hs +7/−0
- test/testdata/addPackageTest/invalid/AddPackage.hs +2/−0
- test/testdata/addPragmas/AfterShebang.hs +12/−0
- test/testdata/addPragmas/NamedFieldPuns.hs +9/−0
- test/testdata/addPragmas/NeedsPragmas.hs +16/−0
- test/testdata/addPragmas/TypeApplications.hs +5/−0
- test/testdata/addPragmas/hie.yaml +6/−0
- test/testdata/badProjects/cabal/Foo.hs +4/−0
- test/testdata/badProjects/cabal/bad-cabal.cabal +16/−0
- test/testdata/cabal-helper/implicit-exe/Setup.hs +2/−0
- test/testdata/cabal-helper/implicit-exe/cabal.project +1/−0
- test/testdata/cabal-helper/implicit-exe/implicit-exe.cabal +17/−0
- test/testdata/cabal-helper/implicit-exe/src/Exe.hs +4/−0
- test/testdata/cabal-helper/implicit-exe/src/Lib.hs +4/−0
- test/testdata/cabal-helper/mono-repo/A/A.cabal +15/−0
- test/testdata/cabal-helper/mono-repo/A/Main.hs +8/−0
- test/testdata/cabal-helper/mono-repo/A/MyLib.hs +4/−0
- test/testdata/cabal-helper/mono-repo/A/Setup.hs +2/−0
- test/testdata/cabal-helper/mono-repo/B/B.cabal +15/−0
- test/testdata/cabal-helper/mono-repo/B/Main.hs +8/−0
- test/testdata/cabal-helper/mono-repo/B/MyLib.hs +4/−0
- test/testdata/cabal-helper/mono-repo/B/Setup.hs +2/−0
- test/testdata/cabal-helper/mono-repo/C/C.cabal +9/−0
- test/testdata/cabal-helper/mono-repo/C/MyLib.hs +4/−0
- test/testdata/cabal-helper/mono-repo/C/Setup.hs +2/−0
- test/testdata/cabal-helper/mono-repo/cabal.project +4/−0
- test/testdata/cabal-helper/multi-source-dirs/Setup.hs +2/−0
- test/testdata/cabal-helper/multi-source-dirs/multi-source-dirs.cabal +11/−0
- test/testdata/cabal-helper/multi-source-dirs/src/BetterLib.hs +5/−0
- test/testdata/cabal-helper/multi-source-dirs/src/input/Lib.hs +6/−0
- test/testdata/cabal-helper/simple-cabal/MyLib.hs +4/−0
- test/testdata/cabal-helper/simple-cabal/Setup.hs +2/−0
- test/testdata/cabal-helper/simple-cabal/simple-cabal-test.cabal +10/−0
- test/testdata/cabal-helper/simple-stack/MyLib.hs +4/−0
- test/testdata/cabal-helper/simple-stack/Setup.hs +2/−0
- test/testdata/cabal-helper/simple-stack/simple-stack-test.cabal +10/−0
- test/testdata/cabal-helper/sub-package/Setup.hs +2/−0
- test/testdata/cabal-helper/sub-package/app/Main.hs +8/−0
- test/testdata/cabal-helper/sub-package/plugins-api/PluginLib.hs +4/−0
- test/testdata/cabal-helper/sub-package/plugins-api/Setup.hs +2/−0
- test/testdata/cabal-helper/sub-package/plugins-api/plugins-api.cabal +10/−0
- test/testdata/cabal-helper/sub-package/src/MyLib.hs +6/−0
- test/testdata/cabal-helper/sub-package/sub-package.cabal +17/−0
- test/testdata/completion/Completion.hs +9/−0
- test/testdata/completion/Context.hs +4/−0
- test/testdata/completion/DupRecFields.hs +5/−0
- test/testdata/completion/completions.cabal +10/−0
- test/testdata/completion/hie.yaml +6/−0
- test/testdata/context/ExampleContext.hs +20/−0
- test/testdata/context/Foo/Bar.hs +3/−0
- test/testdata/definition/Bar.hs +3/−0
- test/testdata/definition/Foo.hs +3/−0
- test/testdata/definition/definitions.cabal +10/−0
- test/testdata/format/Format.floskell.formatted.hs +16/−0
- test/testdata/format/Format.floskell.initial.hs +17/−0
- test/testdata/format/Format.formatted_document.hs +16/−0
- test/testdata/format/Format.formatted_document_with_tabsize.hs +16/−0
- test/testdata/format/Format.formatted_range.hs +15/−0
- test/testdata/format/Format.formatted_range_with_tabsize.hs +15/−0
- test/testdata/format/Format.fourmolu.formatted.hs +16/−0
- test/testdata/format/Format.hs +15/−0
- test/testdata/format/Format.ormolu.formatted.hs +16/−0
- test/testdata/format/Format.ormolu_post_floskell.formatted.hs +16/−0
- test/testdata/format/Format2.fourmolu.formatted.hs +5/−0
- test/testdata/format/Format2.hs +5/−0
- test/testdata/format/Format2.ormolu.formatted.hs +5/−0
- test/testdata/gototest/hie.yaml +6/−0
- test/testdata/gototest/src/Lib.hs +40/−0
- test/testdata/gototest/src/Lib2.hs +13/−0
- test/testdata/hie.yaml +11/−0
- test/testdata/hieBiosError/Foo.hs +1/−0
- test/testdata/hieBiosError/hie.yaml +0/−0
- test/testdata/hieBiosMainIs/Main.hs +4/−0
- test/testdata/hieBiosMainIs/Setup.hs +2/−0
- test/testdata/hieBiosMainIs/hieBiosMainIs.cabal +8/−0
- test/testdata/hlint/ApplyRefact1.hs +5/−0
- test/testdata/hlint/ApplyRefact2.hs +2/−0
- test/testdata/hlint/ApplyRefact3.hs +8/−0
- test/testdata/hlint/ApplyRefact4.hs +5/−0
- test/testdata/hlint/ApplyRefact5.hs +7/−0
- test/testdata/hlint/ApplyRefact6.hs +11/−0
- test/testdata/hlint/cpp/ApplyRefact2.hs +9/−0
- test/testdata/hlint/cpp/ApplyRefact3.hs +7/−0
- test/testdata/hlint/cpp/hie.yaml +7/−0
- test/testdata/hlint/cpp/test.h +1/−0
- test/testdata/hlint/hie.yaml +11/−0
- test/testdata/hlint/ignore/.hlint.yaml +2/−0
- test/testdata/hlint/ignore/ApplyRefact.hs +5/−0
- test/testdata/hlint/ignore/hie.yaml +4/−0
- test/testdata/hlint/lambdacase/ApplyRefact1.hs +4/−0
- test/testdata/hlint/lambdacase/hie.yaml +5/−0
- test/testdata/hlint/typeapps/ApplyRefact1.hs +3/−0
- test/testdata/hlint/typeapps/hie.yaml +5/−0
- test/testdata/liquid/Evens.hs +41/−0
- test/testdata/moduleName/TEmptyModule.hs +2/−0
- test/testdata/moduleName/TEmptyModule.hs.expected +3/−0
- test/testdata/moduleName/TWrongModuleName.hs +7/−0
- test/testdata/moduleName/TWrongModuleName.hs.expected +7/−0
- test/testdata/moduleName/hie.yaml +1/−0
- test/testdata/moduleName/mainlike.hs +0/−0
- test/testdata/moduleName/mainlike.hs.expected +1/−0
- test/testdata/redundantImportTest/hie.yaml +5/−0
- test/testdata/redundantImportTest/src/CodeActionRedundant.hs +5/−0
- test/testdata/redundantImportTest/src/MultipleImports.hs +6/−0
- test/testdata/redundantImportTest/test.cabal +18/−0
- test/testdata/rename/Rename.hs +6/−0
- test/testdata/testdata.cabal +37/−0
- test/testdata/wErrorTest/cabal.project +1/−0
- test/testdata/wErrorTest/dist-newstyle/build/x86_64-linux/ghc-8.10.2/test-0.1.0.0/build/autogen/Paths_test.hs +50/−0
- test/testdata/wErrorTest/dist-newstyle/build/x86_64-linux/ghc-8.10.2/test-0.1.0.0/build/autogen/cabal_macros.h +143/−0
- test/testdata/wErrorTest/dist-newstyle/build/x86_64-linux/ghc-8.10.3/test-0.1.0.0/build/autogen/Paths_test.hs +50/−0
- test/testdata/wErrorTest/dist-newstyle/build/x86_64-linux/ghc-8.10.3/test-0.1.0.0/build/autogen/cabal_macros.h +143/−0
- test/testdata/wErrorTest/hie.yaml +4/−0
- test/testdata/wErrorTest/src/WError.hs +2/−0
- test/testdata/wErrorTest/test.cabal +18/−0
- test/utils/Test/Hls/Command.hs +32/−0
- test/utils/Test/Hls/Util.hs +0/−443
- test/wrapper/Main.hs +29/−35
@@ -1,1048 +1,1333 @@-# Changelog for haskell-language-server - -## 1.0.0 - -This is the celebratory release of Haskell Language Server 1.0.0! -This release includes a lot of internal changes, bug fixes, leaks plugged, and performance improvements, thanks to all our contributors. -Among others, -- We added the support for GHC 8.10.4, and removed the support for GHC 8.10.1 - Afterward, we will support upmost 3 patch versions for each minor version of GHC, if no special situation happens. -- As by hie-bios >= 0.7.3, we use (`${XDG_CACHE_HOME}`)[https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html]`/hie-bios/...` (or similar depends on OS) as a build directory for Cabal. -- Now Eval plugin uses the parsing mechanism of GHC and becomes more stable. -- We supports a code action to disambiguate the same identifiers from multiple imports. -  -- We supports a code action to hide shadowed identifiers from import. -  -- HIE DB is now integrated. This means we now support `find-references`, `workspace-symbol`. `find-definition` is also improved in a project with multiple components. -- Brittany and Stylish-haskell plugins now load language extensions from the ghc session. -- Tactic plugin supports eta-reduction and Agda-like split tactic and can create a function with piecewise definitions. -  - -### Pull requests merged for 1.0.0 - -- Correctly split non-varpats in tactics -([#1427](https://github.com/haskell/haskell-language-server/pull/1427)) by @isovector -- Move tactics tests to be standalone -([#1425](https://github.com/haskell/haskell-language-server/pull/1425)) by @isovector -- Fix the handling of default HLS config again -([#1419](https://github.com/haskell/haskell-language-server/pull/1419)) by @pepeiborra -- Patch pre-commit-hook to work with GHCIDE/hls-plugin-api codes -([#1418](https://github.com/haskell/haskell-language-server/pull/1418)) by @Ailrun -- Refactor pragmas plugin -([#1417](https://github.com/haskell/haskell-language-server/pull/1417)) by @berberman -- Add a test for #1376 -([#1414](https://github.com/haskell/haskell-language-server/pull/1414)) by @pepeiborra -- Reenable HLS example benchmark -([#1412](https://github.com/haskell/haskell-language-server/pull/1412)) by @pepeiborra -- Fix pre-commit-hook -([#1411](https://github.com/haskell/haskell-language-server/pull/1411)) by @Ailrun -- Plugin Config: Add maxCompletions to JSON instance -([#1407](https://github.com/haskell/haskell-language-server/pull/1407)) by @andys8 -- Remove custom 'trim' implementation -([#1406](https://github.com/haskell/haskell-language-server/pull/1406)) by @fendor -- Update to hie-bios 0.7.4 -([#1405](https://github.com/haskell/haskell-language-server/pull/1405)) by @fendor -- Prepare 1.0.0 release -([#1402](https://github.com/haskell/haskell-language-server/pull/1402)) by @Ailrun -- Fix install script after hlint fixes -([#1400](https://github.com/haskell/haskell-language-server/pull/1400)) by @jhrcek -- Use last with-utf8 to fix #1372 -([#1399](https://github.com/haskell/haskell-language-server/pull/1399)) by @jneira -- Implement Tactic Featuresets -([#1398](https://github.com/haskell/haskell-language-server/pull/1398)) by @isovector -- Update hie-bios -([#1397](https://github.com/haskell/haskell-language-server/pull/1397)) by @Ailrun -- Bump plugins versions -([#1392](https://github.com/haskell/haskell-language-server/pull/1392)) by @pepeiborra -- Split main Tactics module -([#1391](https://github.com/haskell/haskell-language-server/pull/1391)) by @isovector -- Prepare ghcide release 0.7.5 -([#1389](https://github.com/haskell/haskell-language-server/pull/1389)) by @pepeiborra -- Disable HLS benchmark example -([#1388](https://github.com/haskell/haskell-language-server/pull/1388)) by @pepeiborra -- Fix GenChangelog script format -([#1387](https://github.com/haskell/haskell-language-server/pull/1387)) by @Ailrun -- Tone down some logInfos to logDebug -([#1385](https://github.com/haskell/haskell-language-server/pull/1385)) by @pepeiborra -- Add a pre commit hook for code formatting -([#1384](https://github.com/haskell/haskell-language-server/pull/1384)) by @Ailrun -- remove unsafePerformIO -([#1383](https://github.com/haskell/haskell-language-server/pull/1383)) by @pepeiborra -- Use object code for TH+UnboxedTuples/Sums -([#1382](https://github.com/haskell/haskell-language-server/pull/1382)) by @wz1000 -- Update stack resolvers 8.10.3/8.10.4 -([#1380](https://github.com/haskell/haskell-language-server/pull/1380)) by @jneira -- Agda-style case splitting for tactics -([#1379](https://github.com/haskell/haskell-language-server/pull/1379)) by @isovector -- Configuration for initial ghc lib dir -([#1378](https://github.com/haskell/haskell-language-server/pull/1378)) by @pepeiborra -- Use lsp-1.1.1 -([#1377](https://github.com/haskell/haskell-language-server/pull/1377)) by @wz1000 -- use implicit-hie cradle from setInitialDynFlags -([#1375](https://github.com/haskell/haskell-language-server/pull/1375)) by @wz1000 -- Add test for multi-component goto def and make runLanguageServer responsible for hiedb -([#1373](https://github.com/haskell/haskell-language-server/pull/1373)) by @wz1000 -- Show window message when auto extending import lists -([#1371](https://github.com/haskell/haskell-language-server/pull/1371)) by @berberman -- Another extension that Brittany cannot parse -([#1369](https://github.com/haskell/haskell-language-server/pull/1369)) by @pepeiborra -- Clean dependency data structures and speed up GetDependencies -([#1368](https://github.com/haskell/haskell-language-server/pull/1368)) by @pepeiborra -- Catch GHC errors in listing module names -([#1367](https://github.com/haskell/haskell-language-server/pull/1367)) by @berberman -- Lose the ghc-lib flag -([#1366](https://github.com/haskell/haskell-language-server/pull/1366)) by @pepeiborra -- Make StylishHaskell plugin recognize extensions from DynFlags -([#1364](https://github.com/haskell/haskell-language-server/pull/1364)) by @Ailrun -- Pass language extensions to Brittany -([#1362](https://github.com/haskell/haskell-language-server/pull/1362)) by @pepeiborra -- Sanitize the setup of the default Ide.Config -([#1361](https://github.com/haskell/haskell-language-server/pull/1361)) by @pepeiborra -- Fix completion snippets on DuplicateRecordFields -([#1360](https://github.com/haskell/haskell-language-server/pull/1360)) by @berberman -- Index files on first open -([#1358](https://github.com/haskell/haskell-language-server/pull/1358)) by @wz1000 -- Make find-definition work better with multi-components -([#1357](https://github.com/haskell/haskell-language-server/pull/1357)) by @wz1000 -- Construct record datacons in tactics -([#1356](https://github.com/haskell/haskell-language-server/pull/1356)) by @isovector -- Don't insert parentheses for top-level tactics holes -([#1352](https://github.com/haskell/haskell-language-server/pull/1352)) by @isovector -- Simplify extracts after running tactics -([#1351](https://github.com/haskell/haskell-language-server/pull/1351)) by @isovector -- Fix code actions regression -([#1349](https://github.com/haskell/haskell-language-server/pull/1349)) by @pepeiborra -- Refactor the hypothesis type in hls-tactics-plugin -([#1347](https://github.com/haskell/haskell-language-server/pull/1347)) by @isovector -- Fix the Eval plugin sporadic exceptions -([#1345](https://github.com/haskell/haskell-language-server/pull/1345)) by @pepeiborra -- Eval Plugin: Proper handling of flags in `:set` -([#1343](https://github.com/haskell/haskell-language-server/pull/1343)) by @konn -- Cancel earlier queued benchmarks -([#1339](https://github.com/haskell/haskell-language-server/pull/1339)) by @pepeiborra -- Default main for ghcide -([#1338](https://github.com/haskell/haskell-language-server/pull/1338)) by @pepeiborra -- Fix duplication of code actions for adding NamedFieldPuns -([#1334](https://github.com/haskell/haskell-language-server/pull/1334)) by @berberman -- Bump explicit-imports plugin -([#1333](https://github.com/haskell/haskell-language-server/pull/1333)) by @pepeiborra -- Add support for ghc-8.10.4 and drop it for ghc-8.10.1 -([#1331](https://github.com/haskell/haskell-language-server/pull/1331)) by @jneira -- Prepare ghcide v0.7.4 release -([#1328](https://github.com/haskell/haskell-language-server/pull/1328)) by @pepeiborra -- Add a new benchmark example to characterise multi-component performance -([#1326](https://github.com/haskell/haskell-language-server/pull/1326)) by @pepeiborra -- [shake-bench] extract project dependencies action (for the HEAD binary) -([#1325](https://github.com/haskell/haskell-language-server/pull/1325)) by @pepeiborra -- [shake-bench] collect eventlogs -([#1324](https://github.com/haskell/haskell-language-server/pull/1324)) by @pepeiborra -- [benchmark] add warmups -([#1323](https://github.com/haskell/haskell-language-server/pull/1323)) by @pepeiborra -- Add code action for hiding shadowed identifiers from imports -([#1322](https://github.com/haskell/haskell-language-server/pull/1322)) by @berberman -- Parallelize benchmark CI -([#1320](https://github.com/haskell/haskell-language-server/pull/1320)) by @pepeiborra -- Fix space leak on cradle reloads -([#1316](https://github.com/haskell/haskell-language-server/pull/1316)) by @pepeiborra -- [benchmarks] speed up CI -([#1315](https://github.com/haskell/haskell-language-server/pull/1315)) by @pepeiborra -- [benchmark] check digests for input files only -([#1314](https://github.com/haskell/haskell-language-server/pull/1314)) by @pepeiborra -- Add link to hackage package to readme -([#1313](https://github.com/haskell/haskell-language-server/pull/1313)) by @expipiplus1 -- Splice Plugin: preparatory version bump for the next (not 0.9.0) HLS release -([#1312](https://github.com/haskell/haskell-language-server/pull/1312)) by @konn -- hls-splice-plugin-0.3.0.0-prepare -([#1311](https://github.com/haskell/haskell-language-server/pull/1311)) by @konn -- Trigger extending import only when the item is not in scope -([#1309](https://github.com/haskell/haskell-language-server/pull/1309)) by @berberman -- Bum up hls-eval-plugin to 0.2 -([#1305](https://github.com/haskell/haskell-language-server/pull/1305)) by @jneira -- Don't extend import list with child if the parent has been imported as (..) -([#1302](https://github.com/haskell/haskell-language-server/pull/1302)) by @berberman -- Prepare hls hlint plugin 0.2.0 -([#1296](https://github.com/haskell/haskell-language-server/pull/1296)) by @jneira -- Import disambiguation: Corrects handling of fully-applied and one-sided sectioned operators in qualifying strategy -([#1294](https://github.com/haskell/haskell-language-server/pull/1294)) by @konn -- hls-splice-plugin-0.2.0.0 -([#1293](https://github.com/haskell/haskell-language-server/pull/1293)) by @konn -- Bump haddock comments plugin to 0.1.1 -([#1292](https://github.com/haskell/haskell-language-server/pull/1292)) by @berberman -- FindImports typo (minor) -([#1291](https://github.com/haskell/haskell-language-server/pull/1291)) by @andys8 -- Bump up hls-plugin-api to 0.7.0 -([#1290](https://github.com/haskell/haskell-language-server/pull/1290)) by @jneira -- Prepare ghcide v0.7.3 release -([#1289](https://github.com/haskell/haskell-language-server/pull/1289)) by @pepeiborra -- hls-retrie-plugin 0.1.1.0 -([#1288](https://github.com/haskell/haskell-language-server/pull/1288)) by @pepeiborra -- Upgrade to lsp-1.0 -([#1284](https://github.com/haskell/haskell-language-server/pull/1284)) by @wz1000 -- Update IRC Name in README -([#1275](https://github.com/haskell/haskell-language-server/pull/1275)) by @fendor -- Restore code actions order -([#1273](https://github.com/haskell/haskell-language-server/pull/1273)) by @pepeiborra -- Prepare 0.9.0 -([#1271](https://github.com/haskell/haskell-language-server/pull/1271)) by @jneira -- Reenable auto extend imports and drop snippets for infix completions -([#1266](https://github.com/haskell/haskell-language-server/pull/1266)) by @pepeiborra -- ghcide: Implements a CodeAction to disambiguate ambiguous symbols -([#1264](https://github.com/haskell/haskell-language-server/pull/1264)) by @konn -- Doctest comment parsing using module annotations in Eval Plugin -([#1232](https://github.com/haskell/haskell-language-server/pull/1232)) by @konn -- Apply some hlint suggestions, silence some others. -([#1227](https://github.com/haskell/haskell-language-server/pull/1227)) by @peterwicksstringfield -- References via `hiedb` -([#704](https://github.com/haskell/haskell-language-server/pull/704)) by @wz1000 -- Use default config on missing configuration section -([#459](https://github.com/haskell/haskell-language-server/pull/459)) by @aufarg - -## 0.9.0 - -This release includes lot of refactorings and bug fixes over existing features, hlint and eval plugins among others. -It contains a fix for a bug in ghcide involving stale diagnostics (#1204). - -The list of contributors continues to show healthy growth, many thanks to you all! - -And remember, we have a new brand logo, courtesy of @Ailrun :slightly_smiling_face: - - - -### Pull requests merged for 0.9.0 - -- Do not error out on failed rewrite -([#1269](https://github.com/haskell/haskell-language-server/pull/1269)) by @pepeiborra -- Tighten dependency on apply-refact -([#1268](https://github.com/haskell/haskell-language-server/pull/1268)) by @hololeap -- Add the new logos -([#1267](https://github.com/haskell/haskell-language-server/pull/1267)) by @Ailrun -- Fix a bug in completions -([#1265](https://github.com/haskell/haskell-language-server/pull/1265)) by @pepeiborra -- Produce heap profiles the old fashioned way, from .hp files -([#1261](https://github.com/haskell/haskell-language-server/pull/1261)) by @pepeiborra -- Break down ghcide functionality in HLS plugins -([#1257](https://github.com/haskell/haskell-language-server/pull/1257)) by @pepeiborra -- Enforce max completions over all plugins -([#1256](https://github.com/haskell/haskell-language-server/pull/1256)) by @pepeiborra -- Reorder code actions to put remove redundant imports first -([#1255](https://github.com/haskell/haskell-language-server/pull/1255)) by @pepeiborra -- Update bench.yml to include all the relevant artifacts -([#1254](https://github.com/haskell/haskell-language-server/pull/1254)) by @pepeiborra -- Benchmarks: generate heap profiles -([#1253](https://github.com/haskell/haskell-language-server/pull/1253)) by @pepeiborra -- Add gh workflows badges -([#1251](https://github.com/haskell/haskell-language-server/pull/1251)) by @jneira -- Add dynamic linking common issue -([#1249](https://github.com/haskell/haskell-language-server/pull/1249)) by @jneira -- Add license for hls-tactics-plugin -([#1248](https://github.com/haskell/haskell-language-server/pull/1248)) by @isovector -- Use exact print to extend import lists -([#1246](https://github.com/haskell/haskell-language-server/pull/1246)) by @berberman -- Test apply-refact with TypeApplications -([#1244](https://github.com/haskell/haskell-language-server/pull/1244)) by @jneira -- Add non reversable pragma completion -([#1243](https://github.com/haskell/haskell-language-server/pull/1243)) by @Ailrun -- Delete redundant "category: Development". -([#1241](https://github.com/haskell/haskell-language-server/pull/1241)) by @peterwicksstringfield -- Complete the No- variants of language extensions and Strict extension -([#1238](https://github.com/haskell/haskell-language-server/pull/1238)) by @mrBliss -- Add code actions for disabling a warning in the current file -([#1235](https://github.com/haskell/haskell-language-server/pull/1235)) by @georgefst -- Change packages metadata and rename tactics subfolder -([#1234](https://github.com/haskell/haskell-language-server/pull/1234)) by @jneira -- Fix the bug that generating comments would duplicate existing comments -([#1233](https://github.com/haskell/haskell-language-server/pull/1233)) by @berberman -- Delete global hie.yaml config -([#1230](https://github.com/haskell/haskell-language-server/pull/1230)) by @jneira -- Easy hlint fixes -([#1226](https://github.com/haskell/haskell-language-server/pull/1226)) by @peterwicksstringfield -- Use the runtime ghc libdir for ghc-exactprint -([#1225](https://github.com/haskell/haskell-language-server/pull/1225)) by @jneira -- Add note in README/Tutorial regarding CPP support -([#1224](https://github.com/haskell/haskell-language-server/pull/1224)) by @tittoassini -- Test and fix for issue 1213 -([#1223](https://github.com/haskell/haskell-language-server/pull/1223)) by @tittoassini -- Add traces for HLS providers -([#1222](https://github.com/haskell/haskell-language-server/pull/1222)) by @pepeiborra -- Use exact print for suggest missing constraint code actions -([#1221](https://github.com/haskell/haskell-language-server/pull/1221)) by @pepeiborra -- Fix changelog dates -([#1220](https://github.com/haskell/haskell-language-server/pull/1220)) by @pepeiborra -- Ignore .shake folder -([#1219](https://github.com/haskell/haskell-language-server/pull/1219)) by @pepeiborra -- Limit completions to top 40 -([#1218](https://github.com/haskell/haskell-language-server/pull/1218)) by @pepeiborra -- Parenthesise type operators when extending import lists -([#1212](https://github.com/haskell/haskell-language-server/pull/1212)) by @mrBliss -- Expose shake options used -([#1209](https://github.com/haskell/haskell-language-server/pull/1209)) by @pepeiborra -- Prepare ghcide release v0.7.1 -([#1207](https://github.com/haskell/haskell-language-server/pull/1207)) by @pepeiborra -- Documentation for the Eval Plugin -([#1206](https://github.com/haskell/haskell-language-server/pull/1206)) by @tittoassini -- Stale diagnostics fix -([#1204](https://github.com/haskell/haskell-language-server/pull/1204)) by @pepeiborra -- Extract Development.IDE.GHC.ExactPrint -([#1203](https://github.com/haskell/haskell-language-server/pull/1203)) by @pepeiborra -- Fix bug in Retrie "fold/unfold in local file" commands -([#1202](https://github.com/haskell/haskell-language-server/pull/1202)) by @pepeiborra -- Minor eval plugin fixes -([#1199](https://github.com/haskell/haskell-language-server/pull/1199)) by @tittoassini -- Disable win 8.6.4 job -([#1198](https://github.com/haskell/haskell-language-server/pull/1198)) by @jneira -- Add custom cache layer for session loading -([#1197](https://github.com/haskell/haskell-language-server/pull/1197)) by @fendor -- Use completionSnippetsOn flag -([#1195](https://github.com/haskell/haskell-language-server/pull/1195)) by @takoeight0821 -- Remove runs dropped by #1173 -([#1194](https://github.com/haskell/haskell-language-server/pull/1194)) by @jneira -- Remove undefined exports suggestions -([#1193](https://github.com/haskell/haskell-language-server/pull/1193)) by @kderme -- Update nixpkgs to ghc 8.10.3 -([#1191](https://github.com/haskell/haskell-language-server/pull/1191)) by @pepeiborra -- Do not disable parallel GC -([#1190](https://github.com/haskell/haskell-language-server/pull/1190)) by @pepeiborra -- Switch module outline to useWtihStale -([#1189](https://github.com/haskell/haskell-language-server/pull/1189)) by @pepeiborra -- Fix sticky diagnostics -([#1188](https://github.com/haskell/haskell-language-server/pull/1188)) by @pepeiborra -- Fix class plugin cabal -([#1186](https://github.com/haskell/haskell-language-server/pull/1186)) by @Ailrun -- Update package description of haddock comments plugin -([#1185](https://github.com/haskell/haskell-language-server/pull/1185)) by @berberman -- Installation from Hackage - add README section -([#1183](https://github.com/haskell/haskell-language-server/pull/1183)) by @pepeiborra -- Preparation for Uploading Splice Plugin to Hackage -([#1182](https://github.com/haskell/haskell-language-server/pull/1182)) by @konn -- Preparation for uploading `hls-exactprint-utils` -([#1181](https://github.com/haskell/haskell-language-server/pull/1181)) by @konn -- Complete hls-hlint-plugin package metadata -([#1180](https://github.com/haskell/haskell-language-server/pull/1180)) by @jneira -- Benchmark improvements -([#1178](https://github.com/haskell/haskell-language-server/pull/1178)) by @pepeiborra -- Make adding missing constraint work in presence of 'forall' (fixes #1164) -([#1177](https://github.com/haskell/haskell-language-server/pull/1177)) by @jhrcek -- Prepare for Hackage -([#1176](https://github.com/haskell/haskell-language-server/pull/1176)) by @pepeiborra -- Test only last ghc minor version and fix windows cache -([#1173](https://github.com/haskell/haskell-language-server/pull/1173)) by @jneira -- Fix toMethodName bug of the Class plugin -([#1170](https://github.com/haskell/haskell-language-server/pull/1170)) by @Ailrun -- Quick fix for #1158 -([#1166](https://github.com/haskell/haskell-language-server/pull/1166)) by @Ailrun -- Suggest adding pragmas for parse errors too -([#1165](https://github.com/haskell/haskell-language-server/pull/1165)) by @mrBliss -- Fix wrong component name of splice plugin in hie.yaml -([#1162](https://github.com/haskell/haskell-language-server/pull/1162)) by @berberman -- Revert "Auto cancel redundant workflows (attempt #2)" -([#1156](https://github.com/haskell/haskell-language-server/pull/1156)) by @pepeiborra -- Auto cancel redundant workflows (attempt #2) -([#1154](https://github.com/haskell/haskell-language-server/pull/1154)) by @pepeiborra -- Prepare 0.8.0 (versions) -([#1153](https://github.com/haskell/haskell-language-server/pull/1153)) by @jneira -- Streamline CircleCI jobs -([#1152](https://github.com/haskell/haskell-language-server/pull/1152)) by @pepeiborra -- Mergify: create configuration -([#1151](https://github.com/haskell/haskell-language-server/pull/1151)) by @jneira -- Bump haskell-lsp to 0.23 -([#1146](https://github.com/haskell/haskell-language-server/pull/1146)) by @berberman -- Remove no longer needed git submodule update -([#1145](https://github.com/haskell/haskell-language-server/pull/1145)) by @jhrcek -- Enable more tests -([#1143](https://github.com/haskell/haskell-language-server/pull/1143)) by @peterwicksstringfield -- Update links to issues/PRs in ghcide tests. -([#1142](https://github.com/haskell/haskell-language-server/pull/1142)) by @peterwicksstringfield -- Fix #723 (Instance declarations in hs-boot files result in GHC errors) -([#781](https://github.com/haskell/haskell-language-server/pull/781)) by @nitros12 -- Also suggest importing methods without parent class -([#766](https://github.com/haskell/haskell-language-server/pull/766)) by @mrBliss -- Delete unused utilities for controlling logging. -([#764](https://github.com/haskell/haskell-language-server/pull/764)) by @peterwicksstringfield -- Delete unused testdata -([#763](https://github.com/haskell/haskell-language-server/pull/763)) by @peterwicksstringfield -- Fix suggestAddTypeAnnotation regex -([#760](https://github.com/haskell/haskell-language-server/pull/760)) by @kderme -- Splice Plugin: expands TH splices and QuasiQuotes -([#759](https://github.com/haskell/haskell-language-server/pull/759)) by @konn -- Haddock comments plugin -([#673](https://github.com/haskell/haskell-language-server/pull/673)) by @berberman -- Leverage last apply-refact improvements in hlint plugin (include getParsedModuleWithComments in ghcide) -([#635](https://github.com/haskell/haskell-language-server/pull/635)) by @jneira - -## 0.8.0 - -- This version adds support for ghc-8.10.3 -- `hls-plugin-api` has been bumped to 0.6.0.0 and `ghcide` has been bumped from 0.6.0.1 to 0.7.0.0. -- It has a new brand plugin: hls-class-plugin, which helps to write class instances - - - -- The eval plugin has been revamped, adding these new features: - - Tests in both plain comments and Haddock comments - - For Haddock comments: shows differences between latest and previous result - - Setup section, executed before every test - - Execution of a section/group of tests at the time - - Property testing - - Setup of GHC extensions -- A new tactic to generate automatically `Arbitrary` instances has been added to tactic plugin -- There had been lot of internal changes: - - ghcide lives now directly in this repository - - the test suite has been cleaned and improved (continuing the work done in 0.7.0) - - -Thanks to all contributors and happy new year! - -### Pull requests merged for 0.8.0 - -- Ci fixes -([#783](https://github.com/haskell/haskell-language-server/pull/783)) by @pepeiborra -- Fix extend imports regression -([#769](https://github.com/haskell/haskell-language-server/pull/769)) by @pepeiborra -- Cleanup format testfiles -([#765](https://github.com/haskell/haskell-language-server/pull/765)) by @peterwicksstringfield -- Retry a failed cradle if the cradle descriptor changes -([#762](https://github.com/haskell/haskell-language-server/pull/762)) by @pepeiborra -- Perform memory measurement on SIGUSR1 -([#761](https://github.com/haskell/haskell-language-server/pull/761)) by @pepeiborra -- Add ghc-8.10.3 support after merging ghcide repo -([#721](https://github.com/haskell/haskell-language-server/pull/721)) by @jneira -- Merge ghcide repository (replacing the submodule) -([#702](https://github.com/haskell/haskell-language-server/pull/702)) by @pepeiborra -- Invert the dependency between hls-plugin-api and ghcide -([#701](https://github.com/haskell/haskell-language-server/pull/701)) by @pepeiborra -- Move eval plugin to hls-eval-plugin -([#700](https://github.com/haskell/haskell-language-server/pull/700)) by @tittoassini -- Fix and enable progress message tests. -([#698](https://github.com/haskell/haskell-language-server/pull/698)) by @peterwicksstringfield -- Add a known tactic for writing arbitrary instances -([#695](https://github.com/haskell/haskell-language-server/pull/695)) by @isovector -- Introduce generic config for plugins -([#691](https://github.com/haskell/haskell-language-server/pull/691)) by @alanz -- Enable get type definition tests -([#690](https://github.com/haskell/haskell-language-server/pull/690)) by @peterwicksstringfield -- Fix ghc version for windows 8.10.2.2 in github build workflow -([#688](https://github.com/haskell/haskell-language-server/pull/688)) by @jneira -- Add plugins conditionally at compile time -([#687](https://github.com/haskell/haskell-language-server/pull/687)) by @jneira -- Implement basic Class plugin -([#661](https://github.com/haskell/haskell-language-server/pull/661)) by @Ailrun -- Extended Eval Plugin -([#438](https://github.com/haskell/haskell-language-server/pull/438)) by @tittoassini - -## 0.7.1 - -- This is a minor bug fix release: - - It fixes an issue that removed accidentally desugarer warnings (#676). - - It disables auto extend import lists in completions, see #679. - -### Pull requests merged for 0.7.1 - -- Disable auto extend import lists in completions. It fixes #679. -([#685](https://github.com/haskell/haskell-language-server/pull/685)) by @pepeiborra -- Restore kick (#676). It fixes #676. -([#677](https://github.com/haskell/haskell-language-server/pull/677)) by @wz1000 -- README: Remove instructions to execute data target -([#675](https://github.com/haskell/haskell-language-server/pull/675)) by @andys8 -- Add hlint tests over cpp, extensions and ignore hints -([#674](https://github.com/haskell/haskell-language-server/pull/674)) by @jneira - -## 0.7.0 - -- This version contains mainly refactors and updates of upstream packages -- It bumps up some formatter versions: - - ormolu is 0.1.4.1 - - fourmolu is 0.3.0.0 - - brittany is 0.13.1.0 -- It uses last implicit-hie-cradle-0.3.0.2, with some [bug](https://github.com/Avi-D-coder/implicit-hie/issues/29) [fixes](https://github.com/Avi-D-coder/implicit-hie/issues/30) -- It uses last ghcide-0.6.0.1 with [improvements and bug fixes](https://github.com/haskell/ghcide/blob/master/CHANGELOG.md#060-2020-12-06): - - Do not enable every "unnecessary" warning by default - - Improvements over completions: - - record fields - - identifiers not in explicit import lists - - extend explicit import list automatically - -Thanks to all haskell-language-server, ghcide and other upstream packages contributors (the list continue growing healthy) for make this release possible. - -### Pull requests merged for 0.7.0 - -- Miscellanous fixes: correct tactic plugin package metadata and cabal.hie.yaml/stack.hie.yaml -([#672](https://github.com/haskell/haskell-language-server/pull/672)) by @berberman -- Remove unnecessary pluginId setting and user Better Map functions in tactics plugin -([#669](https://github.com/haskell/haskell-language-server/pull/669)) by @jhrcek -- Do not suggest explicitly disabled pragmas -([#666](https://github.com/haskell/haskell-language-server/pull/666)) by @berberman -- fixed hie.yaml.stack -([#664](https://github.com/haskell/haskell-language-server/pull/664)) by @tittoassini -- Add pragmas completions -([#662](https://github.com/haskell/haskell-language-server/pull/662)) by @gdevanla -- Enable code completion tests -([#657](https://github.com/haskell/haskell-language-server/pull/657)) by @peterwicksstringfield -- Enable highlight unittests -([#656](https://github.com/haskell/haskell-language-server/pull/656)) by @peterwicksstringfield -- Fix document symbols unit tests. -([#655](https://github.com/haskell/haskell-language-server/pull/655)) by @peterwicksstringfield -- Delete duplicate cabal clause for applyrefact2 -([#654](https://github.com/haskell/haskell-language-server/pull/654)) by @peterwicksstringfield -- Add extra-source-files for split plugins -([#650](https://github.com/haskell/haskell-language-server/pull/650)) by @berberman -- [nix-shell] Actually use gitignore -([#649](https://github.com/haskell/haskell-language-server/pull/649)) by @pepeiborra -- idempotent command and code cleanup -([#648](https://github.com/haskell/haskell-language-server/pull/648)) by @tittoassini -- Split the Imports and Retrie plugins -([#647](https://github.com/haskell/haskell-language-server/pull/647)) by @pepeiborra -- Simplify and Bump implicit-hie version constraints -([#645](https://github.com/haskell/haskell-language-server/pull/645)) by @Avi-D-coder -- Fix and enable disabled code action unit tests, fix fallback handler -([#643](https://github.com/haskell/haskell-language-server/pull/643)) by @peterwicksstringfield -- Add Ghcide hie.yaml instruction for Stack users -([#641](https://github.com/haskell/haskell-language-server/pull/641)) by @Sir4ur0n -- Upgrade the Nix build system -([#639](https://github.com/haskell/haskell-language-server/pull/639)) by @pepeiborra -- No longer needed to build once for Stack -([#637](https://github.com/haskell/haskell-language-server/pull/637)) by @Sir4ur0n -- Preserve the last empty comment line after eval plugin -([#631](https://github.com/haskell/haskell-language-server/pull/631)) by @expipiplus1 -- Update fourmolu to 0.3.0.0 -([#624](https://github.com/haskell/haskell-language-server/pull/624)) by @gwils -- Add hspec-discover to build-tool-depends in tactics plugin -([#623](https://github.com/haskell/haskell-language-server/pull/623)) by @gwils -- Add build to ghc-8.10.2 and windows -([#619](https://github.com/haskell/haskell-language-server/pull/619)) by @jneira -- Module Name Plugin: Treat modules starting with lowercase as Main module -([#616](https://github.com/haskell/haskell-language-server/pull/616)) by @konn -- Bump ormolu to 0.1.4.1 -([#614](https://github.com/haskell/haskell-language-server/pull/614)) by @AlistairB -- Fix fourmolu plugin inconsistent formatting -([#599](https://github.com/haskell/haskell-language-server/pull/599)) by @zweimach -- Hlint: bring over idea2Message for formatting -([#598](https://github.com/haskell/haskell-language-server/pull/598)) by @alanz -- Makes dictionary argument exclusion logic in Tactic plugin more robust -([#508](https://github.com/haskell/haskell-language-server/pull/508)) by @konn - -## 0.6.0 - -0.6.0 includes two brand new plugins! - -- [Hlint Plugin](https://github.com/haskell/haskell-language-server/pull/166): it integrates hlint diagnostics and lets you apply suggestions to fix them. - - - -- [Module Name Plugin](https://github.com/haskell/haskell-language-server/pull/480): it makes easier create new modules and modify them, suggesting the appropiate module name as a code lens. - - - -This release also includes many improvements and bug fixes for the tactic plugin (see pull requests authored by @isovector for more details). - -We have updated two essential tools used by the ide: - -- `implicit-hie`: [to fix a bug](https://github.com/haskell/haskell-language-server/issues/498) present when loading cabal based projects with executables containing `other-modules` - -- `ghcide`: the ide uses [the just released version 0.5](https://github.com/haskell/ghcide/blob/master/CHANGELOG.md#050-2020-10-08) with many bug fixes and improvements, including: - - code action to remove *all* redundant imports - - improved support for Template Haskell - - emit desugarer warnings - -### Pull requests merged for 0.6.0 - -- Fix tasty rerun -([#570](https://github.com/haskell/haskell-language-server/pull/570)) by @jneira -- Bump up ghcide submodule to version 0.5.0 -([#568](https://github.com/haskell/haskell-language-server/pull/568)) by @jneira -- Refactor tactics to track hypothesis provenance -([#557](https://github.com/haskell/haskell-language-server/pull/557)) by @isovector -- Use bash shell to allow its idioms -([#552](https://github.com/haskell/haskell-language-server/pull/552)) by @jneira -- Ignore flakey tactics test -([#546](https://github.com/haskell/haskell-language-server/pull/546)) by @isovector -- Better scoring metric for deriving safeHead -([#545](https://github.com/haskell/haskell-language-server/pull/545)) by @isovector -- Discover skolems in the hypothesis, not just goal -([#542](https://github.com/haskell/haskell-language-server/pull/542)) by @isovector -- [retrie] Fix code action title -([#538](https://github.com/haskell/haskell-language-server/pull/538)) by @pepeiborra -- Tactics support for using given constraints -([#534](https://github.com/haskell/haskell-language-server/pull/534)) by @isovector -- Add missing tactic subpackage in default stack.yaml -([#529](https://github.com/haskell/haskell-language-server/pull/529)) by @jneira -- Use implicit-hie-0.1.2.0 -([#528](https://github.com/haskell/haskell-language-server/pull/528)) by @jneira -- Wait for diagnostics in tactics tests -([#525](https://github.com/haskell/haskell-language-server/pull/525)) by @isovector -- Fix a bug in tactics preventing split of split -([#520](https://github.com/haskell/haskell-language-server/pull/520)) by @isovector -- Use infix notation for destructing and splitting infix data cons -([#519](https://github.com/haskell/haskell-language-server/pull/519)) by @isovector -- Retry the build three times -([#518](https://github.com/haskell/haskell-language-server/pull/518)) by @jneira -- Separate tactics into its own package -([#516](https://github.com/haskell/haskell-language-server/pull/516)) by @isovector -- Add a Troubleshooting section to the README -([#507](https://github.com/haskell/haskell-language-server/pull/507)) by @michaelpj -- Add GitHub Actions CI for testing -([#504](https://github.com/haskell/haskell-language-server/pull/504)) by @bubba -- Fix stack build for ghc-8.8.3 failing on some machines -([#503](https://github.com/haskell/haskell-language-server/pull/503)) by @luntain -- Expand explanation of how to configure HLS -([#497](https://github.com/haskell/haskell-language-server/pull/497)) by @michaelpj -- Module Name Plugin -([#480](https://github.com/haskell/haskell-language-server/pull/480)) by @tittoassini -- Allow hole filling to deal with recursion -([#472](https://github.com/haskell/haskell-language-server/pull/472)) by @isovector -- Restrict editor config to Haskell file, to avoid affecting Makefiles or other tab-based formats -([#442](https://github.com/haskell/haskell-language-server/pull/442)) by @tittoassini -- Hlint plugin using ghc-lib -([#166](https://github.com/haskell/haskell-language-server/pull/166)) by @jneira - -## 0.5.1 - -0.5.1 is a minor bug fix release, mainly fixing an issue with the eval plugin -as well as upgrading the ormolu and stylish-haskell dependencies. - -### Pull requests merged for 0.5.1 - -- Minimal fix for eval regression -([#488](https://github.com/haskell/haskell-language-server/pull/488)) by @pepeiborra -- Bump stylish-haskell to 0.12.2.0 -([#482](https://github.com/haskell/haskell-language-server/pull/482)) by @maksbotan -- Improve the emacs instructions a little -([#479](https://github.com/haskell/haskell-language-server/pull/479)) by @michaelpj -- Update README: HLS is no longer in *very* early stage -([#475](https://github.com/haskell/haskell-language-server/pull/475)) by @Anrock -- Tactic plugin: Excludes Dictionary arguments in GADTs in Destruct Tactic -([#474](https://github.com/haskell/haskell-language-server/pull/474)) by @konn -- Update doom emacs install instructions in README -([#470](https://github.com/haskell/haskell-language-server/pull/470)) by @iyefrat -- Add ghc-8.10.2 to circleci -([#464](https://github.com/haskell/haskell-language-server/pull/464)) by @jneira -- Bump ormolu to 0.1.3.0 -([#422](https://github.com/haskell/haskell-language-server/pull/422)) by @AlistairB - -## 0.5.0 - -0.5.0 comes with a new tactics plugin which provides case splitting, homomorphic case splitting, and lambda introduction: - - - -It can even attempt to fully fill a hole! - - - -The imports lens plugin also learnt a new code action to make all imports explicit: - - - -There's also plenty of bug fixes, improvements and updates to the underlying tools, including Fourmolu, implicit-hie-cradle and ghcide. [Some of the improvements from ghcide](https://github.com/haskell/ghcide/releases/tag/v0.4.0) include: - -- The entire project is typechecked on load -- Reverse dependencies of a module are typechecked upon saving -- Code completion includes local terms -- Import code actions now also suggest open imports -- Documentation on hover shows for symbols defined in the same module - -If you're eager to try all this out, haskell-language-server is now also installable via [ghcup](https://www.haskell.org/ghcup/): - -```shell -$ ghcup install hls -``` - -### Pull requests merged for 0.5.0 - -- Update GHC version 8.12 to 9.0 in README -([#460](https://github.com/haskell/haskell-language-server/pull/460)) by @maralorn -- Update Fourmolu to 0.2 -([#455](https://github.com/haskell/haskell-language-server/pull/455)) by @georgefst -- Generate .gz tars of all the binaries for macOS and Linux in GitHub Actions -([#454](https://github.com/haskell/haskell-language-server/pull/454)) by @bubba -- install: create hls hardlinks instead of copies except on Windows -([#451](https://github.com/haskell/haskell-language-server/pull/451)) by @juhp -- wrapper: cd to --cwd earlier -([#448](https://github.com/haskell/haskell-language-server/pull/448)) by @ocharles -- Update README.md -([#446](https://github.com/haskell/haskell-language-server/pull/446)) by @moodmosaic -- Upate Emacs setup notes -([#440](https://github.com/haskell/haskell-language-server/pull/440)) by @gdevanla -- Use ghcide master and prepare hls-plugin-api-0.4.1.0 -([#439](https://github.com/haskell/haskell-language-server/pull/439)) by @jneira -- Add a code action to make all imports explicit -([#436](https://github.com/haskell/haskell-language-server/pull/436)) by @pepeiborra -- Add docs on how to choose a formatter -([#432](https://github.com/haskell/haskell-language-server/pull/432)) by @googleson78 -- Implement 'Attempt to fill hole' code action -([#431](https://github.com/haskell/haskell-language-server/pull/431)) by @TOTBWF -- Clarify that eval is a lens -([#428](https://github.com/haskell/haskell-language-server/pull/428)) by @Anrock -- Use implicit-hie-cradle-0.2.0.1 -([#427](https://github.com/haskell/haskell-language-server/pull/427)) by @jneira -- [retrie] Fix uris in workspace edit -([#424](https://github.com/haskell/haskell-language-server/pull/424)) by @pepeiborra -- Separate paragraphs -([#423](https://github.com/haskell/haskell-language-server/pull/423)) by @jneira -- Include .editorconfig in the contributing section -([#420](https://github.com/haskell/haskell-language-server/pull/420)) by @jneira -- Mention the copy of executables wit ghc version -([#419](https://github.com/haskell/haskell-language-server/pull/419)) by @jneira -- Eval plugin: proper multilined results handling and command-name abbreviations -([#413](https://github.com/haskell/haskell-language-server/pull/413)) by @konn -- Retrie - calculate imports in the command handler -([#408](https://github.com/haskell/haskell-language-server/pull/408)) by @pepeiborra -- Progress reporting for Eval plugin -([#398](https://github.com/haskell/haskell-language-server/pull/398)) by @pepeiborra -- bump ghcide submodule -([#396](https://github.com/haskell/haskell-language-server/pull/396)) by @wz1000 -- Fix cradles -([#393](https://github.com/haskell/haskell-language-server/pull/393)) by @pepeiborra -- Case splitting and lambda introduction -([#391](https://github.com/haskell/haskell-language-server/pull/391)) by @isovector -- Use stale data in explicit imports lens -([#383](https://github.com/haskell/haskell-language-server/pull/383)) by @pepeiborra -- Create hls-plugin-api and move plugins to exe -([#379](https://github.com/haskell/haskell-language-server/pull/379)) by @jneira -- Rebase on ghcide HEAD -([#378](https://github.com/haskell/haskell-language-server/pull/378)) by @pepeiborra -- README clarify how exactly to use code evaluation -([#377](https://github.com/haskell/haskell-language-server/pull/377)) by @DunetsNM -- Revise README.md -([#374](https://github.com/haskell/haskell-language-server/pull/374)) by @gihyeonsung - -## 0.4.0 - -0.4.0 introduces the import lens plugin, which can convert your import statements into qualified imports, or into an explicit import list: - - - -The eval plugin has also learnt two new commands, `:type` and `:kind`: - -```haskell -{-# LANGUAGE TypeApplications #-} -foo :: Show a => a -> String -foo = show - --- >>> :type foo @Int --- foo @Int :: Int -> String - --- >>> :type +v foo @Int --- foo @Int :: Show Int => Int -> String -``` - -```haskell --- >>> type N = 1 --- >>> type M = 40 --- >>> :kind N + M + 1 --- N + M + 1 :: Nat - --- >>> type N = 1 --- >>> type M = 40 --- >>> :kind N + M + 1 --- N + M + 1 :: Nat -``` - -There is now also support for GHC 8.10.2, and a new `haskell-language-server --probe-tools` command to help debug what version of each tool HLS is using. - -```shell -$ haskell-language-server --probe-tools -haskell-language-server version: 0.3.0.0 (GHC: 8.10.1) (PATH: /Users/luke/.cabal/store/ghc-8.10.1/hskll-lngg-srvr-0.3.0.0-7c6d48c3/bin/haskell-language-server) -Tool versions found on the $PATH -cabal: 3.2.0.0 -stack: 2.3.3 -ghc: 8.10.2 -``` - -### Pull requests merged for 0.4.0 - -- Bring over a [tutorial about how to add hls plugins](https://github.com/pepeiborra/hls-tutorial) -([#372](https://github.com/haskell/haskell-language-server/pull/372)) by @bubba -- Update the ghcide upstream to be in haskell/ghcide -([#370](https://github.com/haskell/haskell-language-server/pull/370)) by @alanz -- Add ISSUE_TEMPLATE for github -([#305](https://github.com/haskell/haskell-language-server/pull/305)) by @fendor -- Add use-package to the list of emacs packages -([#343](https://github.com/haskell/haskell-language-server/pull/343)) by @rgleichman -- Implements `:type [+v/+d]` in Eval Plugin -([#361](https://github.com/haskell/haskell-language-server/pull/361)) by @konn -- Bump bounds of hie-bios to 0.7.0 -([#357](https://github.com/haskell/haskell-language-server/pull/357)) by @maralorn -- Fix ImportLens plugin to work with GHC 8.10 -([#356](https://github.com/haskell/haskell-language-server/pull/356)) by @Ailrun -- Add single file rewrites and ignore unknown files -([#321](https://github.com/haskell/haskell-language-server/pull/321)) by @pepeiborra -- Do not suggest explicit import lists for qualified imports -([#354](https://github.com/haskell/haskell-language-server/pull/354)) by @expipiplus1 -- Explicit imports lens (as seen on Twitter) -([#310](https://github.com/haskell/haskell-language-server/pull/310)) by @pepeiborra -- Adds `:kind` and `:kind!` commands to Eval Plugin -([#345](https://github.com/haskell/haskell-language-server/pull/345)) by @konn -- tech(nix): update niv and remove allowbroken -([#350](https://github.com/haskell/haskell-language-server/pull/350)) by @willbush -- Update VS Code Haskell URL/repo -([#338](https://github.com/haskell/haskell-language-server/pull/338)) by @Sir4ur0n -- doc(hack): Add explanation to hack and test HLS -([#329](https://github.com/haskell/haskell-language-server/pull/329)) by @Sir4ur0n -- Apply the module pragmas for evaluation -([#322](https://github.com/haskell/haskell-language-server/pull/322)) by @pepeiborra -- Copy working stack-8.6.5.yaml to stack.yaml -([#332](https://github.com/haskell/haskell-language-server/pull/332)) by @jneira -- tech(nix): Allow broken as retrie is marked as broken -([#331](https://github.com/haskell/haskell-language-server/pull/331)) by @Sir4ur0n -- feat(git): Add install/hie.yaml to gitignore -([#328](https://github.com/haskell/haskell-language-server/pull/328)) by @Sir4ur0n -- Replace wrong occurrences of "engine" by "server" -([#319](https://github.com/haskell/haskell-language-server/pull/319)) by @tchoutri -- Simplify coc.nvim instructions -([#315](https://github.com/haskell/haskell-language-server/pull/315)) by @oblitum -- Coc config file requires a {} nesting everything -([#317](https://github.com/haskell/haskell-language-server/pull/317)) by @hyiltiz -- Restrict opentelemetry version for stack builds -([#312](https://github.com/haskell/haskell-language-server/pull/312)) by @jneira -- Add support for ghc-8.10.2 -([#308](https://github.com/haskell/haskell-language-server/pull/308)) by @jneira -- Return nothing if tool is not on the PATH -([#309](https://github.com/haskell/haskell-language-server/pull/309)) by @fendor -- Probe tools cli -([#306](https://github.com/haskell/haskell-language-server/pull/306)) by @fendor -- Add fourmolu plugin (attempt 2) and add Brittany for ghc-8.10.1 -([#264](https://github.com/haskell/haskell-language-server/pull/264)) by @georgefst - -## 0.3.0 - -0.3.0 comes with two new plugins, retrie and fourmolu, provides binaries for -GHC 8.8.4, and comes with a host of bug fixes. - -The retrie plugin supports RULES, functions and type synonyms which can be -accessed through contextual code actions. - -Fourmolu can be used to format your code by setting the -`haskell.formattingProvider` field in your LSP configuration to - -```json -{ - "haskell": { - "formattingProvider": "fourmolu" - } -} -``` - -The Brittany formatter is now also available on GHC 8.10.1. - -### Pull requests merged - -- Fix haddock parse error in install.hs -([#255](https://github.com/haskell/haskell-language-server/pull/255)) by @georgefst -- Ormolu flags -([#246](https://github.com/haskell/haskell-language-server/pull/246)) by @pepeiborra -- Ormolu fix -([#257](https://github.com/haskell/haskell-language-server/pull/257)) by @sureyeaah -- Remove redundant CircleCI steps -([#259](https://github.com/haskell/haskell-language-server/pull/259)) by @bubba -- Slow down Tasty by limiting it to -j1 -([#261](https://github.com/haskell/haskell-language-server/pull/261)) by @bubba -- Remove hspec-expectations -([#260](https://github.com/haskell/haskell-language-server/pull/260)) by @bubba -- Remove a redundant caching step -([#262](https://github.com/haskell/haskell-language-server/pull/262)) by @Ailrun -- add hie.yaml to coc configuration -([#267](https://github.com/haskell/haskell-language-server/pull/267)) by @sureyeaah -- Initial Retrie plugin -([#266](https://github.com/haskell/haskell-language-server/pull/266)) by @pepeiborra -- Add exe extension to win executables -([#284](https://github.com/haskell/haskell-language-server/pull/284)) by @jneira -- Use wz1000/hls-3 ghcide branch -([#275](https://github.com/haskell/haskell-language-server/pull/275)) by @alanz -- Fix rename capability being declared -([#285](https://github.com/haskell/haskell-language-server/pull/285)) by @bubba -- Add CI job for 8.8.4 -([#287](https://github.com/haskell/haskell-language-server/pull/287)) by @bubba -- Make the AGPL flag manual in cabal -([#250](https://github.com/haskell/haskell-language-server/pull/250)) by @fendor -- Bring in doc URL fix for Windows -([#289](https://github.com/haskell/haskell-language-server/pull/289)) by @bubba -- Bring in fix for libm on Linux static binaries -([#293](https://github.com/haskell/haskell-language-server/pull/293)) by @bubba -- Add fourmolu plugin (attempt 2) and add Brittany for ghc-8.10.1 -([#264](https://github.com/haskell/haskell-language-server/pull/264)) by @georgefst -- Trying new hls-3 branch -([#300](https://github.com/haskell/haskell-language-server/pull/300)) by @alanz - -## 0.2.2 - -This changes the configuration section from "languageServerHaskell" to "haskell" -to align it with vscode-haskell-1.0.0. Whilst the old section is still -supported for now, you should update your LSP configuration (which varies per -client) from - -```json -{ - "languageServerHaskell": { - "formattingProvider": "stylish-haskell" - } -} -``` - -to - -```json -{ - "haskell": { - "formattingProvider": "stylish-haskell" - } -} -``` - -### Pull requests merged for 0.2.2 - -- Mention docs on hover feature in README -([#209](https://github.com/haskell/haskell-language-server/pull/209)) by @georgefst -- Add static binaries for ghc-8.8.4 -([#224](https://github.com/haskell/haskell-language-server/pull/224)) by @bubba -- Rename the configuration section from languageServerHaskell => haskell -([#227](https://github.com/haskell/haskell-language-server/pull/227)) by @bubba -- Use -haddock for cabal and stack -([#214](https://github.com/haskell/haskell-language-server/pull/214)) by @jneira -- slightly better shell.nix for local development -([#235](https://github.com/haskell/haskell-language-server/pull/235)) by @pepeiborra -- Shell nix further steps -([#240](https://github.com/haskell/haskell-language-server/pull/240)) by @pepeiborra -- Add numeric-version option for wrapper and server -([#241](https://github.com/haskell/haskell-language-server/pull/241)) by @fendor -- Accept the legacy "languageServerHaskell" config name -([#243](https://github.com/haskell/haskell-language-server/pull/243)) by @bubba -- Fix for Eval plugin: Error from tests not reported -([#244](https://github.com/haskell/haskell-language-server/pull/244)) by @tittoassini -- Rename binaries before uploading -([#248](https://github.com/haskell/haskell-language-server/pull/248)) by @bubba - -## 0.2.1 - -This release includes a new eval plugin that allows Haddock code examples to be -evaluated through a code lens. For example, the code below will now offer to -evaluate `intercalate " " example`, and will insert the output in the line -below. - -```haskell -example :: [String] -example = ["This is an example", "of", "interactive", "evaluation"] - --- >>> intercalate " " example --- "This is an example of interactive evaluation" --- -``` - -This is also the first release to have binaries distributed alongside it. Some -behind the scene changes include the GHC library directory now being obtained on -the fly, so either `ghc`, `cabal` or `stack` will need to be present on your -PATH depending on your project. See `docs/releases.md` for more information. If -you find any issues with this, please let us know! - -### Pull requests merged for 0.2.1 - -- Bump ormolu to 0.1.2.0 -([#189](https://github.com/haskell/haskell-language-server/pull/189)) by @AlistairB -- Remove dependency on Cabal -([#195](https://github.com/haskell/haskell-language-server/pull/195)) by @bubba -- Fix extraneous extra-dep in stack-8.6.4.yaml -([#199](https://github.com/haskell/haskell-language-server/pull/199)) by @bubba -- Fix install script stack targets -([#203](https://github.com/haskell/haskell-language-server/pull/203)) by @jneira -- Add support for ghc-8.8.4 -([#206](https://github.com/haskell/haskell-language-server/pull/206)) by @jneira -- Simple Eval plugin -([#191](https://github.com/haskell/haskell-language-server/pull/191)) by @pepeiborra -- Distributable binaries -([#165](https://github.com/haskell/haskell-language-server/pull/165)) by @bubba - -## 0.2 - -- Use cabal-plan from Hackage -([#185](https://github.com/haskell/haskell-language-server/pull/185)) by @georgefst -- Bump ghcide to wz1000 hls-2 branch -([#184](https://github.com/haskell/haskell-language-server/pull/184)) by @alanz -- doc(preprocessor): Document the preprocessor limitation -([#177](https://github.com/haskell/haskell-language-server/pull/177)) by @Sir4ur0n -- Use shell.nix from Haskell-IDE-Engine -([#169](https://github.com/haskell/haskell-language-server/pull/169)) by @fendor -- Remove last occurrences of shake.yaml -([#163](https://github.com/haskell/haskell-language-server/pull/163)) by @fendor -- Use an unique install/stack.yaml -([#154](https://github.com/haskell/haskell-language-server/pull/154)) by @jneira -- Introduce golden testing -([#152](https://github.com/haskell/haskell-language-server/pull/152)) by @Ailrun -- Revert "Use bullet as separator instead of HR" -([#150](https://github.com/haskell/haskell-language-server/pull/150)) by @alanz -- feat(hie-bios): Multi-cradle, ignore directories -([#147](https://github.com/haskell/haskell-language-server/pull/147)) by @Sir4ur0n -- [Plugin] stylish-haskell formatter -([#146](https://github.com/haskell/haskell-language-server/pull/146)) by @Ailrun -- Separate ghcide tests and disable them for now -([#137](https://github.com/haskell/haskell-language-server/pull/137)) by @jneira -- Convert private lib in common stanza -([#136](https://github.com/haskell/haskell-language-server/pull/136)) by @jneira -- Add zlibc to readme -([#134](https://github.com/haskell/haskell-language-server/pull/134)) by @Sir4ur0n -- Complete editor integrations -([#132](https://github.com/haskell/haskell-language-server/pull/132)) by @jneira -- Remove inexistent component from hie.yaml.stack -([#131](https://github.com/haskell/haskell-language-server/pull/131)) by @jneira -- Bump to new mpickering/ghcide -([#130](https://github.com/haskell/haskell-language-server/pull/130)) by @alanz -- Update ghc-lib-parser version -([#129](https://github.com/haskell/haskell-language-server/pull/129)) by @jneira -- Remove redundant import -([#128](https://github.com/haskell/haskell-language-server/pull/128)) by @bubba -- Default the number of Shake threads to 0 (automatic) -([#127](https://github.com/haskell/haskell-language-server/pull/127)) by @bubba -- Added kakoune integration instructions -([#125](https://github.com/haskell/haskell-language-server/pull/125)) by @414owen -- Fix install script dev target -([#124](https://github.com/haskell/haskell-language-server/pull/124)) by @jneira -- Add plugin support for Rename providers -([#123](https://github.com/haskell/haskell-language-server/pull/123)) by @pepeiborra -- Add jobs for stack and cabal using ghc-8.10.1 -([#120](https://github.com/haskell/haskell-language-server/pull/120)) by @jneira -- Add lower bound to tasty-ant-xml -([#119](https://github.com/haskell/haskell-language-server/pull/119)) by @jneira -- Fix build using brittany revision -([#117](https://github.com/haskell/haskell-language-server/pull/117)) by @jneira -- Use floskell released version 0.10.3 -([#116](https://github.com/haskell/haskell-language-server/pull/116)) by @jneira -- Add emacs/doom-emacs integration sub-section -([#115](https://github.com/haskell/haskell-language-server/pull/115)) by @yuanw -- Port hie README partially -([#112](https://github.com/haskell/haskell-language-server/pull/112)) by @jneira -- Use cabal-helper-1.1, add stack-8.10.1.yaml and unify cabal.project's -([#108](https://github.com/haskell/haskell-language-server/pull/108)) by @jneira -- [#87] Fix completion via ghcide's `getCompletionsLSP` -([#107](https://github.com/haskell/haskell-language-server/pull/107)) by @korayal -- Create specific project file for ghc-8.10. -([#106](https://github.com/haskell/haskell-language-server/pull/106)) by @jneira -- Issue 5 - Move HIE Tests and convert to Tasty -([#105](https://github.com/haskell/haskell-language-server/pull/105)) by @jeffwindsor -- Hls update latest hie bios -([#100](https://github.com/haskell/haskell-language-server/pull/100)) by @fendor -- Update extra-deps to use latest fork version of shake -([#98](https://github.com/haskell/haskell-language-server/pull/98)) by @fendor -- Activate typechecking in non-lsp mode -([#95](https://github.com/haskell/haskell-language-server/pull/95)) by @jneira -- Fix haddock parsing errors -([#92](https://github.com/haskell/haskell-language-server/pull/92)) by @jneira -- Update for haskell-lsp 0.22 -([#89](https://github.com/haskell/haskell-language-server/pull/89)) by @alanz -- Get building with ghc-8.10 -([#83](https://github.com/haskell/haskell-language-server/pull/83)) by @bubba - -## 0.1 - -### In this version - -- cabal to 2020-05-02T10:11:15Z -- stack-8.8.3 to lts-15.10 -- stack to nightly-2020-05-01 - -### Changes - -This is the initial version, so too many to list individually. - -The key point is that is now supports multi-component cradles, and has been in -daily use by the developers for some time. - -It still does not have feature parity with `haskell-ide-engine`, but it is -currently useful. +# Changelog for haskell-language-server++## 1.1.0++Haskell Language Server 1.1.0 has finally come! Many thanks to all contributors -- since the last release, we have merged over 100 PRs!+As always, there are many internal bug fixes and performance improvements in ghcide. Apart from that,++* Wingman gets many enhancements, thanks to @isovector for this epic work!+ * Wingman actions can now be bound to editor hotkeys+ * Experimental support for "jump to next unsolved hole"+ * Improved layout algorithm --- don't reflow instances, or break do-blocks+ * Wingman can now deal with GADTs, rank-n types and pattern synonyms+ * Wingman now respects user-written bindings on the left side of the equals sign+ * Significantly more-natural synthesized code when dealing with newtypes, infix operators, records and strings+ * Improved user experience --- less waiting, and friendly errors for when things go wrong+* hlint plugin not working in some cases gets fixed+* annoying log message "haskell-lsp:incoming message parse error" gets fixed in `lsp-1.2`+* eval plugin now supports `it` variable, like GHCi+* verbose message "No cradle found for ... Proceeding with implicit cradle" is GONE+* type lenses plugin now has its custom config `mode` (enum) [`always`] to control its working mode:+ * `always`: always displays type signature lenses of global bindings+ * `exported`: similar to `always`, but only displays for exported global bindings+ * `diagnostics`: follows diagnostic messages produced by GHC+* top-level LSP option `completionSnippetsOn` and `maxNumberOfProblems` are deprecated+* completions plugin now has its custom config:+ * `autoExtendOn` (boolean) [`true`]: whether to enable auto extending import lists+ * `snippetsOn` (boolean) [`true`]: wheter to enable completion snippets, taking the place of `completionSnippetsOn`+* Wingman has its custom config:+ * `timeout_duration` (integer) [`2`]: the timeout for Wingman actions, in seconds+ * `features` (string) [`""`]: feature set used by Wingman (See [the README of Wingman](https://github.com/haskell/haskell-language-server/tree/master/plugins/hls-tactics-plugin#readme))+ * `max_use_ctor_actions` (integer) [`5`]: maximum number of `Use constructor <x>` code actions that can appear+ * `hole_severity` (enum) [`none`]: the severity to use when showing hole diagnostics+* LSP symbols of typeclass and type families are more appropriate+* test suite of plugins are reorganized, which no longer need to be run with `test-server` executable+* two new packages `hls-test-utils` and `hls-stylish-haskell-plugin` are extracted++This version uses `lsp-1.2.0`, `hls-plugin-api-1.1.0`, and `ghcide-1.2.0.2`.++### Pull requests merged for 1.1.0++- Restore compat. with haddock-library 1.8+([#1717](https://github.com/haskell/haskell-language-server/pull/1717)) by @pepeiborra+- Don't suggest destruct actions for already-destructed terms+([#1715](https://github.com/haskell/haskell-language-server/pull/1715)) by @isovector+- Add keybindings and jump to hole to the Wingman README+([#1712](https://github.com/haskell/haskell-language-server/pull/1712)) by @isovector+- Bracketing for snippet completions+([#1709](https://github.com/haskell/haskell-language-server/pull/1709)) by @OliverMadine+- Prepare ghcide 1.2.0+([#1707](https://github.com/haskell/haskell-language-server/pull/1707)) by @berberman+- Adjust bounds+([#1701](https://github.com/haskell/haskell-language-server/pull/1701)) by @berberman+- Update nix+([#1699](https://github.com/haskell/haskell-language-server/pull/1699)) by @berberman+- Wingman: "Destruct all" only on ADTs+([#1695](https://github.com/haskell/haskell-language-server/pull/1695)) by @isovector+- Fix ghcide and HLS enter lsp mode by default+([#1692](https://github.com/haskell/haskell-language-server/pull/1692)) by @berberman+- Decrease Wingman timeout from 3.3 minutes to 2 seconds (configurable)+([#1688](https://github.com/haskell/haskell-language-server/pull/1688)) by @isovector+- Wrap test suite of tactics plugin into tasty test tree+([#1676](https://github.com/haskell/haskell-language-server/pull/1676)) by @berberman+- Wingman: Use infix notation for operator applications+([#1675](https://github.com/haskell/haskell-language-server/pull/1675)) by @isovector+- Ignore ghcide tests by paths+([#1673](https://github.com/haskell/haskell-language-server/pull/1673)) by @jneira+- Ignore nix job steps by path+([#1672](https://github.com/haskell/haskell-language-server/pull/1672)) by @jneira+- Intelligent derivations of Semigroup and Monoid for Wingman+([#1671](https://github.com/haskell/haskell-language-server/pull/1671)) by @isovector+- optimize ambiguity import suggestions+([#1669](https://github.com/haskell/haskell-language-server/pull/1669)) by @July541+- Replace Barrier with MVar in lsp main+([#1668](https://github.com/haskell/haskell-language-server/pull/1668)) by @berberman+- ghcide - enable ApplicativeDo everywhere+([#1667](https://github.com/haskell/haskell-language-server/pull/1667)) by @pepeiborra+- support custom Ide commands+([#1666](https://github.com/haskell/haskell-language-server/pull/1666)) by @pepeiborra+- Add bounds for Diff+([#1665](https://github.com/haskell/haskell-language-server/pull/1665)) by @berberman+- Update shake bounds of install script+([#1664](https://github.com/haskell/haskell-language-server/pull/1664)) by @berberman+- Avoid creating IsFileOfInterest keys for non workspace files+([#1661](https://github.com/haskell/haskell-language-server/pull/1661)) by @pepeiborra+- additional .gitignore entries+([#1659](https://github.com/haskell/haskell-language-server/pull/1659)) by @pepeiborra+- Skip tracing unless eventlog is enabled+([#1658](https://github.com/haskell/haskell-language-server/pull/1658)) by @pepeiborra+- Fix a wingman bug caused by mismanaged stale data+([#1657](https://github.com/haskell/haskell-language-server/pull/1657)) by @isovector+- Fix ignore paths+([#1656](https://github.com/haskell/haskell-language-server/pull/1656)) by @jneira+- Shut the Shake session on exit, instead of restarting it+([#1655](https://github.com/haskell/haskell-language-server/pull/1655)) by @pepeiborra+- Emit holes as diagnostics+([#1653](https://github.com/haskell/haskell-language-server/pull/1653)) by @isovector+- log exceptions before killing the server+([#1651](https://github.com/haskell/haskell-language-server/pull/1651)) by @pepeiborra+- Do not override custom commands+([#1650](https://github.com/haskell/haskell-language-server/pull/1650)) by @pepeiborra+- Fix importing type operators+([#1644](https://github.com/haskell/haskell-language-server/pull/1644)) by @berberman+- Add haskell-language-server-bin to Arch Linux section+([#1642](https://github.com/haskell/haskell-language-server/pull/1642)) by @marcin-rzeznicki+- Update ISSUE_TEMPLATE.md+([#1640](https://github.com/haskell/haskell-language-server/pull/1640)) by @Ailrun+- Civilized indexing progress reporting+([#1633](https://github.com/haskell/haskell-language-server/pull/1633)) by @pepeiborra+- Update to lsp-1.2+([#1631](https://github.com/haskell/haskell-language-server/pull/1631)) by @wz1000+- Avoid reordering plugins+([#1629](https://github.com/haskell/haskell-language-server/pull/1629)) by @pepeiborra+- Run plugins' test suites with server in the same process+([#1628](https://github.com/haskell/haskell-language-server/pull/1628)) by @berberman+- Remove ignored paths+([#1623](https://github.com/haskell/haskell-language-server/pull/1623)) by @jneira+- Update formatting hooks to not include Wingman+([#1622](https://github.com/haskell/haskell-language-server/pull/1622)) by @Ailrun+- Add CPP Options for Stylish Haskell & Brittany Formatters+([#1620](https://github.com/haskell/haskell-language-server/pull/1620)) by @prikhi+- Use custom config for completions plugin+([#1619](https://github.com/haskell/haskell-language-server/pull/1619)) by @berberman+- Configurable I/O handles+([#1617](https://github.com/haskell/haskell-language-server/pull/1617)) by @pepeiborra+- Add installation instructions for Arch Linux+([#1616](https://github.com/haskell/haskell-language-server/pull/1616)) by @berberman+- Properly pass argFiles into defaultMain+([#1613](https://github.com/haskell/haskell-language-server/pull/1613)) by @mpickering+- Migrate tests of plugins+([#1612](https://github.com/haskell/haskell-language-server/pull/1612)) by @berberman+- Allow for customizable Haskell views of Property types+([#1608](https://github.com/haskell/haskell-language-server/pull/1608)) by @isovector+- Extract hls-test-utils+([#1606](https://github.com/haskell/haskell-language-server/pull/1606)) by @berberman+- Add test data files to extra-source-files+([#1605](https://github.com/haskell/haskell-language-server/pull/1605)) by @jneira+- Extract stylish-haskell plugin into a standalone package+([#1604](https://github.com/haskell/haskell-language-server/pull/1604)) by @berberman+- Eval plugin: evaluate expressions as statements+([#1603](https://github.com/haskell/haskell-language-server/pull/1603)) by @berberman+- Bump haddock-library to 1.10.0+([#1598](https://github.com/haskell/haskell-language-server/pull/1598)) by @berberman+- Relax ghcides upper bound on base16-bytestring+([#1595](https://github.com/haskell/haskell-language-server/pull/1595)) by @maralorn+- Use CiInterface/SkInterface for typeclass symbols+([#1592](https://github.com/haskell/haskell-language-server/pull/1592)) by @fwcd+- Avoid duplicating known targets and import paths+([#1590](https://github.com/haskell/haskell-language-server/pull/1590)) by @pepeiborra+- Add ability for plugins to handle file change notifications+([#1588](https://github.com/haskell/haskell-language-server/pull/1588)) by @pepeiborra+- Ensure eval plugin Print class doesn't rely on Prelude being in scope+([#1587](https://github.com/haskell/haskell-language-server/pull/1587)) by @akrmn+- Give a canonical ordering for destructing terms in Wingman+([#1586](https://github.com/haskell/haskell-language-server/pull/1586)) by @isovector+- Try a homomorphic destruct before a standard destruct+([#1582](https://github.com/haskell/haskell-language-server/pull/1582)) by @isovector+- Update homepage and other urls for ghcide+([#1580](https://github.com/haskell/haskell-language-server/pull/1580)) by @felixonmars+- Regularize custom config of plugins+([#1576](https://github.com/haskell/haskell-language-server/pull/1576)) by @berberman+- Cleanup the TacticProviders interface+([#1572](https://github.com/haskell/haskell-language-server/pull/1572)) by @isovector+- Add custom code action kinds for import related code actions+([#1570](https://github.com/haskell/haskell-language-server/pull/1570)) by @berberman+- bump retrie plugin version+([#1569](https://github.com/haskell/haskell-language-server/pull/1569)) by @pepeiborra+- Use ConLikes instead of DataCons+([#1568](https://github.com/haskell/haskell-language-server/pull/1568)) by @isovector+- Remove max number of problems config option+([#1567](https://github.com/haskell/haskell-language-server/pull/1567)) by @jneira+- Prepare ghcide 1.1.0+([#1566](https://github.com/haskell/haskell-language-server/pull/1566)) by @pepeiborra+- Use string literals to synthesize the empty string+([#1564](https://github.com/haskell/haskell-language-server/pull/1564)) by @isovector+- Add wingman branding to code actions+([#1555](https://github.com/haskell/haskell-language-server/pull/1555)) by @isovector+- Use TextEdit to insert new imports+([#1554](https://github.com/haskell/haskell-language-server/pull/1554)) by @berberman+- Introduce strict versions of modifyVar to improve contention+([#1553](https://github.com/haskell/haskell-language-server/pull/1553)) by @pepeiborra+- Improve how wingman uses evidence+([#1549](https://github.com/haskell/haskell-language-server/pull/1549)) by @isovector+- Review early cutoff fingerprints+([#1547](https://github.com/haskell/haskell-language-server/pull/1547)) by @pepeiborra+- Improve thread contention around diagnostics+([#1546](https://github.com/haskell/haskell-language-server/pull/1546)) by @pepeiborra+- Be much more intelligent about splitting matches+([#1543](https://github.com/haskell/haskell-language-server/pull/1543)) by @isovector+- Update nixpkgs to ghc 8.10.4+([#1538](https://github.com/haskell/haskell-language-server/pull/1538)) by @berberman+- Log a warning for every diagnostic received when doDiagnostics=False+([#1537](https://github.com/haskell/haskell-language-server/pull/1537)) by @pepeiborra+- Fix missing parens of auto extending imports+([#1526](https://github.com/haskell/haskell-language-server/pull/1526)) by @berberman+- Change Wingman module structure, address -Wall+([#1519](https://github.com/haskell/haskell-language-server/pull/1519)) by @isovector+- Pull Wingman's method hypotheses directly from in-scope dicts+([#1517](https://github.com/haskell/haskell-language-server/pull/1517)) by @isovector+- Avoid redundant work in diagnostics pass+([#1514](https://github.com/haskell/haskell-language-server/pull/1514)) by @pepeiborra+- Add an option to control progress reporting+([#1513](https://github.com/haskell/haskell-language-server/pull/1513)) by @pepeiborra+- Package ghcide code actions+([#1512](https://github.com/haskell/haskell-language-server/pull/1512)) by @berberman+- Demote implicit cradle warn to logging+([#1511](https://github.com/haskell/haskell-language-server/pull/1511)) by @jneira+- Set all plugin flags to manual+([#1510](https://github.com/haskell/haskell-language-server/pull/1510)) by @jneira+- Avoid always rerunning GetModificationTime for interface files too+([#1506](https://github.com/haskell/haskell-language-server/pull/1506)) by @pepeiborra+- Let Wingman's apply tactic run endomorphisms+([#1505](https://github.com/haskell/haskell-language-server/pull/1505)) by @isovector+- Make Wingman produce user-facing error messages+([#1502](https://github.com/haskell/haskell-language-server/pull/1502)) by @isovector+- Disable HLS benchmarks+([#1501](https://github.com/haskell/haskell-language-server/pull/1501)) by @wz1000+- Add kind and preferred flag for all Wingman code actions+([#1499](https://github.com/haskell/haskell-language-server/pull/1499)) by @isovector+- Organize Wingman tests+([#1498](https://github.com/haskell/haskell-language-server/pull/1498)) by @isovector+- Register IDE configuration when called via the command line+([#1495](https://github.com/haskell/haskell-language-server/pull/1495)) by @wz1000+- Haddock upper bound+([#1492](https://github.com/haskell/haskell-language-server/pull/1492)) by @jneira+- Make type lenses plugin configurable+([#1491](https://github.com/haskell/haskell-language-server/pull/1491)) by @berberman+- Context-aware ExactPrint grafting for HsExpr+([#1489](https://github.com/haskell/haskell-language-server/pull/1489)) by @isovector+- Drive GetModificationTime using watched file events+([#1487](https://github.com/haskell/haskell-language-server/pull/1487)) by @pepeiborra+- Faster ModSummary fingerprints+([#1485](https://github.com/haskell/haskell-language-server/pull/1485)) by @pepeiborra+- Revert all changes to hie-compat since 11b5c2e+([#1484](https://github.com/haskell/haskell-language-server/pull/1484)) by @wz1000+- Fix non-determinism in boot-def test+([#1483](https://github.com/haskell/haskell-language-server/pull/1483)) by @wz1000+- Hackage needs autogen-modules+([#1481](https://github.com/haskell/haskell-language-server/pull/1481)) by @jneira+- Ignore ci for some subdirectories and files+([#1480](https://github.com/haskell/haskell-language-server/pull/1480)) by @jneira+- Split plugin tests into two cabal projects+([#1479](https://github.com/haskell/haskell-language-server/pull/1479)) by @wz1000+- Less aggressive refine tactic+([#1475](https://github.com/haskell/haskell-language-server/pull/1475)) by @isovector+- Enable hls-tactics-plugin tests in CI+([#1474](https://github.com/haskell/haskell-language-server/pull/1474)) by @isovector+- Generate a more robust top-level binding Provenance+([#1473](https://github.com/haskell/haskell-language-server/pull/1473)) by @isovector+- Add new variables to the extract when doing intros+([#1472](https://github.com/haskell/haskell-language-server/pull/1472)) by @isovector+- Bump up hlint plugin version+([#1469](https://github.com/haskell/haskell-language-server/pull/1469)) by @jneira+- Make sure split respects GADT equalities+([#1466](https://github.com/haskell/haskell-language-server/pull/1466)) by @isovector+- Add "Split all function arguments" code action+([#1464](https://github.com/haskell/haskell-language-server/pull/1464)) by @isovector+- Add "Refine hole" code action+([#1463](https://github.com/haskell/haskell-language-server/pull/1463)) by @isovector+- Implement "use constructor" code action+([#1461](https://github.com/haskell/haskell-language-server/pull/1461)) by @isovector+- Remove tactics src-dir from func-test+([#1460](https://github.com/haskell/haskell-language-server/pull/1460)) by @isovector+- Make sure to give the correct DynFlags to the recompilation checker+([#1459](https://github.com/haskell/haskell-language-server/pull/1459)) by @pepeiborra+- Don't use record notation for single-field datacons in tactics+([#1456](https://github.com/haskell/haskell-language-server/pull/1456)) by @isovector+- update IRC channel name in plugin tutorial+([#1455](https://github.com/haskell/haskell-language-server/pull/1455)) by @shapr+- Update readme and cabal for Wingman+([#1454](https://github.com/haskell/haskell-language-server/pull/1454)) by @isovector+- Remove recursion tracking from TacticState+([#1453](https://github.com/haskell/haskell-language-server/pull/1453)) by @isovector+- Use runtime ghc libdir for ghc-exactprint and ghc-8.10+([#1451](https://github.com/haskell/haskell-language-server/pull/1451)) by @jneira+- Simplify tactics state structure+([#1449](https://github.com/haskell/haskell-language-server/pull/1449)) by @isovector+- Extract the qualified name from already imported module+([#1445](https://github.com/haskell/haskell-language-server/pull/1445)) by @berberman+- Correct megaparsec lower bound+([#1441](https://github.com/haskell/haskell-language-server/pull/1441)) by @jneira+- Reformat all files+([#1439](https://github.com/haskell/haskell-language-server/pull/1439)) by @Ailrun+- Customize the unitId used for the fake internal component+([#1435](https://github.com/haskell/haskell-language-server/pull/1435)) by @pepeiborra+- Minor performance optimizations+([#1432](https://github.com/haskell/haskell-language-server/pull/1432)) by @pepeiborra++## 1.0.0++This is the celebratory release of Haskell Language Server 1.0.0!+This release includes a lot of internal changes, bug fixes, leaks plugged, and performance improvements, thanks to all our contributors.+Among others,+- We added the support for GHC 8.10.4, and removed the support for GHC 8.10.1+ Afterward, we will support upmost 3 patch versions for each minor version of GHC, if no special situation happens.+- As by hie-bios >= 0.7.3, we use (`${XDG_CACHE_HOME}`)[https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html]`/hie-bios/...` (or similar depends on OS) as a build directory for Cabal.+- Now Eval plugin uses the parsing mechanism of GHC and becomes more stable.+- We supports a code action to disambiguate the same identifiers from multiple imports.+ +- We supports a code action to hide shadowed identifiers from import.+ +- HIE DB is now integrated. This means we now support `find-references`, `workspace-symbol`. `find-definition` is also improved in a project with multiple components.+- Brittany and Stylish-haskell plugins now load language extensions from the ghc session.+- Tactic plugin supports eta-reduction and Agda-like split tactic and can create a function with piecewise definitions.+ ++### Pull requests merged for 1.0.0++- Correctly split non-varpats in tactics+([#1427](https://github.com/haskell/haskell-language-server/pull/1427)) by @isovector+- Move tactics tests to be standalone+([#1425](https://github.com/haskell/haskell-language-server/pull/1425)) by @isovector+- Fix the handling of default HLS config again+([#1419](https://github.com/haskell/haskell-language-server/pull/1419)) by @pepeiborra+- Patch pre-commit-hook to work with GHCIDE/hls-plugin-api codes+([#1418](https://github.com/haskell/haskell-language-server/pull/1418)) by @Ailrun+- Refactor pragmas plugin+([#1417](https://github.com/haskell/haskell-language-server/pull/1417)) by @berberman+- Add a test for #1376+([#1414](https://github.com/haskell/haskell-language-server/pull/1414)) by @pepeiborra+- Reenable HLS example benchmark+([#1412](https://github.com/haskell/haskell-language-server/pull/1412)) by @pepeiborra+- Fix pre-commit-hook+([#1411](https://github.com/haskell/haskell-language-server/pull/1411)) by @Ailrun+- Plugin Config: Add maxCompletions to JSON instance+([#1407](https://github.com/haskell/haskell-language-server/pull/1407)) by @andys8+- Remove custom 'trim' implementation+([#1406](https://github.com/haskell/haskell-language-server/pull/1406)) by @fendor+- Update to hie-bios 0.7.4+([#1405](https://github.com/haskell/haskell-language-server/pull/1405)) by @fendor+- Prepare 1.0.0 release+([#1402](https://github.com/haskell/haskell-language-server/pull/1402)) by @Ailrun+- Fix install script after hlint fixes+([#1400](https://github.com/haskell/haskell-language-server/pull/1400)) by @jhrcek+- Use last with-utf8 to fix #1372+([#1399](https://github.com/haskell/haskell-language-server/pull/1399)) by @jneira+- Implement Tactic Featuresets+([#1398](https://github.com/haskell/haskell-language-server/pull/1398)) by @isovector+- Update hie-bios+([#1397](https://github.com/haskell/haskell-language-server/pull/1397)) by @Ailrun+- Bump plugins versions+([#1392](https://github.com/haskell/haskell-language-server/pull/1392)) by @pepeiborra+- Split main Tactics module+([#1391](https://github.com/haskell/haskell-language-server/pull/1391)) by @isovector+- Prepare ghcide release 0.7.5+([#1389](https://github.com/haskell/haskell-language-server/pull/1389)) by @pepeiborra+- Disable HLS benchmark example+([#1388](https://github.com/haskell/haskell-language-server/pull/1388)) by @pepeiborra+- Fix GenChangelog script format+([#1387](https://github.com/haskell/haskell-language-server/pull/1387)) by @Ailrun+- Tone down some logInfos to logDebug+([#1385](https://github.com/haskell/haskell-language-server/pull/1385)) by @pepeiborra+- Add a pre commit hook for code formatting+([#1384](https://github.com/haskell/haskell-language-server/pull/1384)) by @Ailrun+- remove unsafePerformIO+([#1383](https://github.com/haskell/haskell-language-server/pull/1383)) by @pepeiborra+- Use object code for TH+UnboxedTuples/Sums+([#1382](https://github.com/haskell/haskell-language-server/pull/1382)) by @wz1000+- Update stack resolvers 8.10.3/8.10.4+([#1380](https://github.com/haskell/haskell-language-server/pull/1380)) by @jneira+- Agda-style case splitting for tactics+([#1379](https://github.com/haskell/haskell-language-server/pull/1379)) by @isovector+- Configuration for initial ghc lib dir+([#1378](https://github.com/haskell/haskell-language-server/pull/1378)) by @pepeiborra+- Use lsp-1.1.1+([#1377](https://github.com/haskell/haskell-language-server/pull/1377)) by @wz1000+- use implicit-hie cradle from setInitialDynFlags+([#1375](https://github.com/haskell/haskell-language-server/pull/1375)) by @wz1000+- Add test for multi-component goto def and make runLanguageServer responsible for hiedb+([#1373](https://github.com/haskell/haskell-language-server/pull/1373)) by @wz1000+- Show window message when auto extending import lists+([#1371](https://github.com/haskell/haskell-language-server/pull/1371)) by @berberman+- Another extension that Brittany cannot parse+([#1369](https://github.com/haskell/haskell-language-server/pull/1369)) by @pepeiborra+- Clean dependency data structures and speed up GetDependencies+([#1368](https://github.com/haskell/haskell-language-server/pull/1368)) by @pepeiborra+- Catch GHC errors in listing module names+([#1367](https://github.com/haskell/haskell-language-server/pull/1367)) by @berberman+- Lose the ghc-lib flag+([#1366](https://github.com/haskell/haskell-language-server/pull/1366)) by @pepeiborra+- Make StylishHaskell plugin recognize extensions from DynFlags+([#1364](https://github.com/haskell/haskell-language-server/pull/1364)) by @Ailrun+- Pass language extensions to Brittany+([#1362](https://github.com/haskell/haskell-language-server/pull/1362)) by @pepeiborra+- Sanitize the setup of the default Ide.Config+([#1361](https://github.com/haskell/haskell-language-server/pull/1361)) by @pepeiborra+- Fix completion snippets on DuplicateRecordFields+([#1360](https://github.com/haskell/haskell-language-server/pull/1360)) by @berberman+- Index files on first open+([#1358](https://github.com/haskell/haskell-language-server/pull/1358)) by @wz1000+- Make find-definition work better with multi-components+([#1357](https://github.com/haskell/haskell-language-server/pull/1357)) by @wz1000+- Construct record datacons in tactics+([#1356](https://github.com/haskell/haskell-language-server/pull/1356)) by @isovector+- Don't insert parentheses for top-level tactics holes+([#1352](https://github.com/haskell/haskell-language-server/pull/1352)) by @isovector+- Simplify extracts after running tactics+([#1351](https://github.com/haskell/haskell-language-server/pull/1351)) by @isovector+- Fix code actions regression+([#1349](https://github.com/haskell/haskell-language-server/pull/1349)) by @pepeiborra+- Refactor the hypothesis type in hls-tactics-plugin+([#1347](https://github.com/haskell/haskell-language-server/pull/1347)) by @isovector+- Fix the Eval plugin sporadic exceptions+([#1345](https://github.com/haskell/haskell-language-server/pull/1345)) by @pepeiborra+- Eval Plugin: Proper handling of flags in `:set`+([#1343](https://github.com/haskell/haskell-language-server/pull/1343)) by @konn+- Cancel earlier queued benchmarks+([#1339](https://github.com/haskell/haskell-language-server/pull/1339)) by @pepeiborra+- Default main for ghcide+([#1338](https://github.com/haskell/haskell-language-server/pull/1338)) by @pepeiborra+- Fix duplication of code actions for adding NamedFieldPuns+([#1334](https://github.com/haskell/haskell-language-server/pull/1334)) by @berberman+- Bump explicit-imports plugin+([#1333](https://github.com/haskell/haskell-language-server/pull/1333)) by @pepeiborra+- Add support for ghc-8.10.4 and drop it for ghc-8.10.1+([#1331](https://github.com/haskell/haskell-language-server/pull/1331)) by @jneira+- Prepare ghcide v0.7.4 release+([#1328](https://github.com/haskell/haskell-language-server/pull/1328)) by @pepeiborra+- Add a new benchmark example to characterise multi-component performance+([#1326](https://github.com/haskell/haskell-language-server/pull/1326)) by @pepeiborra+- [shake-bench] extract project dependencies action (for the HEAD binary)+([#1325](https://github.com/haskell/haskell-language-server/pull/1325)) by @pepeiborra+- [shake-bench] collect eventlogs+([#1324](https://github.com/haskell/haskell-language-server/pull/1324)) by @pepeiborra+- [benchmark] add warmups+([#1323](https://github.com/haskell/haskell-language-server/pull/1323)) by @pepeiborra+- Add code action for hiding shadowed identifiers from imports+([#1322](https://github.com/haskell/haskell-language-server/pull/1322)) by @berberman+- Parallelize benchmark CI+([#1320](https://github.com/haskell/haskell-language-server/pull/1320)) by @pepeiborra+- Fix space leak on cradle reloads+([#1316](https://github.com/haskell/haskell-language-server/pull/1316)) by @pepeiborra+- [benchmarks] speed up CI+([#1315](https://github.com/haskell/haskell-language-server/pull/1315)) by @pepeiborra+- [benchmark] check digests for input files only+([#1314](https://github.com/haskell/haskell-language-server/pull/1314)) by @pepeiborra+- Add link to hackage package to readme+([#1313](https://github.com/haskell/haskell-language-server/pull/1313)) by @expipiplus1+- Splice Plugin: preparatory version bump for the next (not 0.9.0) HLS release+([#1312](https://github.com/haskell/haskell-language-server/pull/1312)) by @konn+- hls-splice-plugin-0.3.0.0-prepare+([#1311](https://github.com/haskell/haskell-language-server/pull/1311)) by @konn+- Trigger extending import only when the item is not in scope+([#1309](https://github.com/haskell/haskell-language-server/pull/1309)) by @berberman+- Bum up hls-eval-plugin to 0.2+([#1305](https://github.com/haskell/haskell-language-server/pull/1305)) by @jneira+- Don't extend import list with child if the parent has been imported as (..)+([#1302](https://github.com/haskell/haskell-language-server/pull/1302)) by @berberman+- Prepare hls hlint plugin 0.2.0+([#1296](https://github.com/haskell/haskell-language-server/pull/1296)) by @jneira+- Import disambiguation: Corrects handling of fully-applied and one-sided sectioned operators in qualifying strategy+([#1294](https://github.com/haskell/haskell-language-server/pull/1294)) by @konn+- hls-splice-plugin-0.2.0.0+([#1293](https://github.com/haskell/haskell-language-server/pull/1293)) by @konn+- Bump haddock comments plugin to 0.1.1+([#1292](https://github.com/haskell/haskell-language-server/pull/1292)) by @berberman+- FindImports typo (minor)+([#1291](https://github.com/haskell/haskell-language-server/pull/1291)) by @andys8+- Bump up hls-plugin-api to 0.7.0+([#1290](https://github.com/haskell/haskell-language-server/pull/1290)) by @jneira+- Prepare ghcide v0.7.3 release+([#1289](https://github.com/haskell/haskell-language-server/pull/1289)) by @pepeiborra+- hls-retrie-plugin 0.1.1.0+([#1288](https://github.com/haskell/haskell-language-server/pull/1288)) by @pepeiborra+- Upgrade to lsp-1.0+([#1284](https://github.com/haskell/haskell-language-server/pull/1284)) by @wz1000+- Update IRC Name in README+([#1275](https://github.com/haskell/haskell-language-server/pull/1275)) by @fendor+- Restore code actions order+([#1273](https://github.com/haskell/haskell-language-server/pull/1273)) by @pepeiborra+- Prepare 0.9.0+([#1271](https://github.com/haskell/haskell-language-server/pull/1271)) by @jneira+- Reenable auto extend imports and drop snippets for infix completions+([#1266](https://github.com/haskell/haskell-language-server/pull/1266)) by @pepeiborra+- ghcide: Implements a CodeAction to disambiguate ambiguous symbols+([#1264](https://github.com/haskell/haskell-language-server/pull/1264)) by @konn+- Doctest comment parsing using module annotations in Eval Plugin+([#1232](https://github.com/haskell/haskell-language-server/pull/1232)) by @konn+- Apply some hlint suggestions, silence some others.+([#1227](https://github.com/haskell/haskell-language-server/pull/1227)) by @peterwicksstringfield+- References via `hiedb`+([#704](https://github.com/haskell/haskell-language-server/pull/704)) by @wz1000+- Use default config on missing configuration section+([#459](https://github.com/haskell/haskell-language-server/pull/459)) by @aufarg++## 0.9.0++This release includes lot of refactorings and bug fixes over existing features, hlint and eval plugins among others.+It contains a fix for a bug in ghcide involving stale diagnostics (#1204).++The list of contributors continues to show healthy growth, many thanks to you all!++And remember, we have a new brand logo, courtesy of @Ailrun :slightly_smiling_face:++++### Pull requests merged for 0.9.0++- Do not error out on failed rewrite+([#1269](https://github.com/haskell/haskell-language-server/pull/1269)) by @pepeiborra+- Tighten dependency on apply-refact+([#1268](https://github.com/haskell/haskell-language-server/pull/1268)) by @hololeap+- Add the new logos+([#1267](https://github.com/haskell/haskell-language-server/pull/1267)) by @Ailrun+- Fix a bug in completions+([#1265](https://github.com/haskell/haskell-language-server/pull/1265)) by @pepeiborra+- Produce heap profiles the old fashioned way, from .hp files+([#1261](https://github.com/haskell/haskell-language-server/pull/1261)) by @pepeiborra+- Break down ghcide functionality in HLS plugins+([#1257](https://github.com/haskell/haskell-language-server/pull/1257)) by @pepeiborra+- Enforce max completions over all plugins+([#1256](https://github.com/haskell/haskell-language-server/pull/1256)) by @pepeiborra+- Reorder code actions to put remove redundant imports first+([#1255](https://github.com/haskell/haskell-language-server/pull/1255)) by @pepeiborra+- Update bench.yml to include all the relevant artifacts+([#1254](https://github.com/haskell/haskell-language-server/pull/1254)) by @pepeiborra+- Benchmarks: generate heap profiles+([#1253](https://github.com/haskell/haskell-language-server/pull/1253)) by @pepeiborra+- Add gh workflows badges+([#1251](https://github.com/haskell/haskell-language-server/pull/1251)) by @jneira+- Add dynamic linking common issue+([#1249](https://github.com/haskell/haskell-language-server/pull/1249)) by @jneira+- Add license for hls-tactics-plugin+([#1248](https://github.com/haskell/haskell-language-server/pull/1248)) by @isovector+- Use exact print to extend import lists+([#1246](https://github.com/haskell/haskell-language-server/pull/1246)) by @berberman+- Test apply-refact with TypeApplications+([#1244](https://github.com/haskell/haskell-language-server/pull/1244)) by @jneira+- Add non reversable pragma completion+([#1243](https://github.com/haskell/haskell-language-server/pull/1243)) by @Ailrun+- Delete redundant "category: Development".+([#1241](https://github.com/haskell/haskell-language-server/pull/1241)) by @peterwicksstringfield+- Complete the No- variants of language extensions and Strict extension+([#1238](https://github.com/haskell/haskell-language-server/pull/1238)) by @mrBliss+- Add code actions for disabling a warning in the current file+([#1235](https://github.com/haskell/haskell-language-server/pull/1235)) by @georgefst+- Change packages metadata and rename tactics subfolder+([#1234](https://github.com/haskell/haskell-language-server/pull/1234)) by @jneira+- Fix the bug that generating comments would duplicate existing comments+([#1233](https://github.com/haskell/haskell-language-server/pull/1233)) by @berberman+- Delete global hie.yaml config+([#1230](https://github.com/haskell/haskell-language-server/pull/1230)) by @jneira+- Easy hlint fixes+([#1226](https://github.com/haskell/haskell-language-server/pull/1226)) by @peterwicksstringfield+- Use the runtime ghc libdir for ghc-exactprint+([#1225](https://github.com/haskell/haskell-language-server/pull/1225)) by @jneira+- Add note in README/Tutorial regarding CPP support+([#1224](https://github.com/haskell/haskell-language-server/pull/1224)) by @tittoassini+- Test and fix for issue 1213+([#1223](https://github.com/haskell/haskell-language-server/pull/1223)) by @tittoassini+- Add traces for HLS providers+([#1222](https://github.com/haskell/haskell-language-server/pull/1222)) by @pepeiborra+- Use exact print for suggest missing constraint code actions+([#1221](https://github.com/haskell/haskell-language-server/pull/1221)) by @pepeiborra+- Fix changelog dates+([#1220](https://github.com/haskell/haskell-language-server/pull/1220)) by @pepeiborra+- Ignore .shake folder+([#1219](https://github.com/haskell/haskell-language-server/pull/1219)) by @pepeiborra+- Limit completions to top 40+([#1218](https://github.com/haskell/haskell-language-server/pull/1218)) by @pepeiborra+- Parenthesise type operators when extending import lists+([#1212](https://github.com/haskell/haskell-language-server/pull/1212)) by @mrBliss+- Expose shake options used+([#1209](https://github.com/haskell/haskell-language-server/pull/1209)) by @pepeiborra+- Prepare ghcide release v0.7.1+([#1207](https://github.com/haskell/haskell-language-server/pull/1207)) by @pepeiborra+- Documentation for the Eval Plugin+([#1206](https://github.com/haskell/haskell-language-server/pull/1206)) by @tittoassini+- Stale diagnostics fix+([#1204](https://github.com/haskell/haskell-language-server/pull/1204)) by @pepeiborra+- Extract Development.IDE.GHC.ExactPrint+([#1203](https://github.com/haskell/haskell-language-server/pull/1203)) by @pepeiborra+- Fix bug in Retrie "fold/unfold in local file" commands+([#1202](https://github.com/haskell/haskell-language-server/pull/1202)) by @pepeiborra+- Minor eval plugin fixes+([#1199](https://github.com/haskell/haskell-language-server/pull/1199)) by @tittoassini+- Disable win 8.6.4 job+([#1198](https://github.com/haskell/haskell-language-server/pull/1198)) by @jneira+- Add custom cache layer for session loading+([#1197](https://github.com/haskell/haskell-language-server/pull/1197)) by @fendor+- Use completionSnippetsOn flag+([#1195](https://github.com/haskell/haskell-language-server/pull/1195)) by @takoeight0821+- Remove runs dropped by #1173+([#1194](https://github.com/haskell/haskell-language-server/pull/1194)) by @jneira+- Remove undefined exports suggestions+([#1193](https://github.com/haskell/haskell-language-server/pull/1193)) by @kderme+- Update nixpkgs to ghc 8.10.3+([#1191](https://github.com/haskell/haskell-language-server/pull/1191)) by @pepeiborra+- Do not disable parallel GC+([#1190](https://github.com/haskell/haskell-language-server/pull/1190)) by @pepeiborra+- Switch module outline to useWtihStale+([#1189](https://github.com/haskell/haskell-language-server/pull/1189)) by @pepeiborra+- Fix sticky diagnostics+([#1188](https://github.com/haskell/haskell-language-server/pull/1188)) by @pepeiborra+- Fix class plugin cabal+([#1186](https://github.com/haskell/haskell-language-server/pull/1186)) by @Ailrun+- Update package description of haddock comments plugin+([#1185](https://github.com/haskell/haskell-language-server/pull/1185)) by @berberman+- Installation from Hackage - add README section+([#1183](https://github.com/haskell/haskell-language-server/pull/1183)) by @pepeiborra+- Preparation for Uploading Splice Plugin to Hackage+([#1182](https://github.com/haskell/haskell-language-server/pull/1182)) by @konn+- Preparation for uploading `hls-exactprint-utils`+([#1181](https://github.com/haskell/haskell-language-server/pull/1181)) by @konn+- Complete hls-hlint-plugin package metadata+([#1180](https://github.com/haskell/haskell-language-server/pull/1180)) by @jneira+- Benchmark improvements+([#1178](https://github.com/haskell/haskell-language-server/pull/1178)) by @pepeiborra+- Make adding missing constraint work in presence of 'forall' (fixes #1164)+([#1177](https://github.com/haskell/haskell-language-server/pull/1177)) by @jhrcek+- Prepare for Hackage+([#1176](https://github.com/haskell/haskell-language-server/pull/1176)) by @pepeiborra+- Test only last ghc minor version and fix windows cache+([#1173](https://github.com/haskell/haskell-language-server/pull/1173)) by @jneira+- Fix toMethodName bug of the Class plugin+([#1170](https://github.com/haskell/haskell-language-server/pull/1170)) by @Ailrun+- Quick fix for #1158+([#1166](https://github.com/haskell/haskell-language-server/pull/1166)) by @Ailrun+- Suggest adding pragmas for parse errors too+([#1165](https://github.com/haskell/haskell-language-server/pull/1165)) by @mrBliss+- Fix wrong component name of splice plugin in hie.yaml+([#1162](https://github.com/haskell/haskell-language-server/pull/1162)) by @berberman+- Revert "Auto cancel redundant workflows (attempt #2)"+([#1156](https://github.com/haskell/haskell-language-server/pull/1156)) by @pepeiborra+- Auto cancel redundant workflows (attempt #2)+([#1154](https://github.com/haskell/haskell-language-server/pull/1154)) by @pepeiborra+- Prepare 0.8.0 (versions)+([#1153](https://github.com/haskell/haskell-language-server/pull/1153)) by @jneira+- Streamline CircleCI jobs+([#1152](https://github.com/haskell/haskell-language-server/pull/1152)) by @pepeiborra+- Mergify: create configuration+([#1151](https://github.com/haskell/haskell-language-server/pull/1151)) by @jneira+- Bump haskell-lsp to 0.23+([#1146](https://github.com/haskell/haskell-language-server/pull/1146)) by @berberman+- Remove no longer needed git submodule update+([#1145](https://github.com/haskell/haskell-language-server/pull/1145)) by @jhrcek+- Enable more tests+([#1143](https://github.com/haskell/haskell-language-server/pull/1143)) by @peterwicksstringfield+- Update links to issues/PRs in ghcide tests.+([#1142](https://github.com/haskell/haskell-language-server/pull/1142)) by @peterwicksstringfield+- Fix #723 (Instance declarations in hs-boot files result in GHC errors)+([#781](https://github.com/haskell/haskell-language-server/pull/781)) by @nitros12+- Also suggest importing methods without parent class+([#766](https://github.com/haskell/haskell-language-server/pull/766)) by @mrBliss+- Delete unused utilities for controlling logging.+([#764](https://github.com/haskell/haskell-language-server/pull/764)) by @peterwicksstringfield+- Delete unused testdata+([#763](https://github.com/haskell/haskell-language-server/pull/763)) by @peterwicksstringfield+- Fix suggestAddTypeAnnotation regex+([#760](https://github.com/haskell/haskell-language-server/pull/760)) by @kderme+- Splice Plugin: expands TH splices and QuasiQuotes+([#759](https://github.com/haskell/haskell-language-server/pull/759)) by @konn+- Haddock comments plugin+([#673](https://github.com/haskell/haskell-language-server/pull/673)) by @berberman+- Leverage last apply-refact improvements in hlint plugin (include getParsedModuleWithComments in ghcide)+([#635](https://github.com/haskell/haskell-language-server/pull/635)) by @jneira++## 0.8.0++- This version adds support for ghc-8.10.3+- `hls-plugin-api` has been bumped to 0.6.0.0 and `ghcide` has been bumped from 0.6.0.1 to 0.7.0.0.+- It has a new brand plugin: hls-class-plugin, which helps to write class instances++++- The eval plugin has been revamped, adding these new features:+ - Tests in both plain comments and Haddock comments+ - For Haddock comments: shows differences between latest and previous result+ - Setup section, executed before every test+ - Execution of a section/group of tests at the time+ - Property testing+ - Setup of GHC extensions+- A new tactic to generate automatically `Arbitrary` instances has been added to tactic plugin+- There had been lot of internal changes:+ - ghcide lives now directly in this repository+ - the test suite has been cleaned and improved (continuing the work done in 0.7.0)+++Thanks to all contributors and happy new year!++### Pull requests merged for 0.8.0++- Ci fixes+([#783](https://github.com/haskell/haskell-language-server/pull/783)) by @pepeiborra+- Fix extend imports regression+([#769](https://github.com/haskell/haskell-language-server/pull/769)) by @pepeiborra+- Cleanup format testfiles+([#765](https://github.com/haskell/haskell-language-server/pull/765)) by @peterwicksstringfield+- Retry a failed cradle if the cradle descriptor changes+([#762](https://github.com/haskell/haskell-language-server/pull/762)) by @pepeiborra+- Perform memory measurement on SIGUSR1+([#761](https://github.com/haskell/haskell-language-server/pull/761)) by @pepeiborra+- Add ghc-8.10.3 support after merging ghcide repo+([#721](https://github.com/haskell/haskell-language-server/pull/721)) by @jneira+- Merge ghcide repository (replacing the submodule)+([#702](https://github.com/haskell/haskell-language-server/pull/702)) by @pepeiborra+- Invert the dependency between hls-plugin-api and ghcide+([#701](https://github.com/haskell/haskell-language-server/pull/701)) by @pepeiborra+- Move eval plugin to hls-eval-plugin+([#700](https://github.com/haskell/haskell-language-server/pull/700)) by @tittoassini+- Fix and enable progress message tests.+([#698](https://github.com/haskell/haskell-language-server/pull/698)) by @peterwicksstringfield+- Add a known tactic for writing arbitrary instances+([#695](https://github.com/haskell/haskell-language-server/pull/695)) by @isovector+- Introduce generic config for plugins+([#691](https://github.com/haskell/haskell-language-server/pull/691)) by @alanz+- Enable get type definition tests+([#690](https://github.com/haskell/haskell-language-server/pull/690)) by @peterwicksstringfield+- Fix ghc version for windows 8.10.2.2 in github build workflow+([#688](https://github.com/haskell/haskell-language-server/pull/688)) by @jneira+- Add plugins conditionally at compile time+([#687](https://github.com/haskell/haskell-language-server/pull/687)) by @jneira+- Implement basic Class plugin+([#661](https://github.com/haskell/haskell-language-server/pull/661)) by @Ailrun+- Extended Eval Plugin+([#438](https://github.com/haskell/haskell-language-server/pull/438)) by @tittoassini++## 0.7.1++- This is a minor bug fix release:+ - It fixes an issue that removed accidentally desugarer warnings (#676).+ - It disables auto extend import lists in completions, see #679.++### Pull requests merged for 0.7.1++- Disable auto extend import lists in completions. It fixes #679.+([#685](https://github.com/haskell/haskell-language-server/pull/685)) by @pepeiborra+- Restore kick (#676). It fixes #676.+([#677](https://github.com/haskell/haskell-language-server/pull/677)) by @wz1000+- README: Remove instructions to execute data target+([#675](https://github.com/haskell/haskell-language-server/pull/675)) by @andys8+- Add hlint tests over cpp, extensions and ignore hints+([#674](https://github.com/haskell/haskell-language-server/pull/674)) by @jneira++## 0.7.0++- This version contains mainly refactors and updates of upstream packages+- It bumps up some formatter versions:+ - ormolu is 0.1.4.1+ - fourmolu is 0.3.0.0+ - brittany is 0.13.1.0+- It uses last implicit-hie-cradle-0.3.0.2, with some [bug](https://github.com/Avi-D-coder/implicit-hie/issues/29) [fixes](https://github.com/Avi-D-coder/implicit-hie/issues/30)+- It uses last ghcide-0.6.0.1 with [improvements and bug fixes](https://github.com/haskell/ghcide/blob/master/CHANGELOG.md#060-2020-12-06):+ - Do not enable every "unnecessary" warning by default+ - Improvements over completions:+ - record fields+ - identifiers not in explicit import lists+ - extend explicit import list automatically++Thanks to all haskell-language-server, ghcide and other upstream packages contributors (the list continue growing healthy) for make this release possible.++### Pull requests merged for 0.7.0++- Miscellanous fixes: correct tactic plugin package metadata and cabal.hie.yaml/stack.hie.yaml+([#672](https://github.com/haskell/haskell-language-server/pull/672)) by @berberman+- Remove unnecessary pluginId setting and user Better Map functions in tactics plugin+([#669](https://github.com/haskell/haskell-language-server/pull/669)) by @jhrcek+- Do not suggest explicitly disabled pragmas+([#666](https://github.com/haskell/haskell-language-server/pull/666)) by @berberman+- fixed hie.yaml.stack+([#664](https://github.com/haskell/haskell-language-server/pull/664)) by @tittoassini+- Add pragmas completions+([#662](https://github.com/haskell/haskell-language-server/pull/662)) by @gdevanla+- Enable code completion tests+([#657](https://github.com/haskell/haskell-language-server/pull/657)) by @peterwicksstringfield+- Enable highlight unittests+([#656](https://github.com/haskell/haskell-language-server/pull/656)) by @peterwicksstringfield+- Fix document symbols unit tests.+([#655](https://github.com/haskell/haskell-language-server/pull/655)) by @peterwicksstringfield+- Delete duplicate cabal clause for applyrefact2+([#654](https://github.com/haskell/haskell-language-server/pull/654)) by @peterwicksstringfield+- Add extra-source-files for split plugins+([#650](https://github.com/haskell/haskell-language-server/pull/650)) by @berberman+- [nix-shell] Actually use gitignore+([#649](https://github.com/haskell/haskell-language-server/pull/649)) by @pepeiborra+- idempotent command and code cleanup+([#648](https://github.com/haskell/haskell-language-server/pull/648)) by @tittoassini+- Split the Imports and Retrie plugins+([#647](https://github.com/haskell/haskell-language-server/pull/647)) by @pepeiborra+- Simplify and Bump implicit-hie version constraints+([#645](https://github.com/haskell/haskell-language-server/pull/645)) by @Avi-D-coder+- Fix and enable disabled code action unit tests, fix fallback handler+([#643](https://github.com/haskell/haskell-language-server/pull/643)) by @peterwicksstringfield+- Add Ghcide hie.yaml instruction for Stack users+([#641](https://github.com/haskell/haskell-language-server/pull/641)) by @Sir4ur0n+- Upgrade the Nix build system+([#639](https://github.com/haskell/haskell-language-server/pull/639)) by @pepeiborra+- No longer needed to build once for Stack+([#637](https://github.com/haskell/haskell-language-server/pull/637)) by @Sir4ur0n+- Preserve the last empty comment line after eval plugin+([#631](https://github.com/haskell/haskell-language-server/pull/631)) by @expipiplus1+- Update fourmolu to 0.3.0.0+([#624](https://github.com/haskell/haskell-language-server/pull/624)) by @gwils+- Add hspec-discover to build-tool-depends in tactics plugin+([#623](https://github.com/haskell/haskell-language-server/pull/623)) by @gwils+- Add build to ghc-8.10.2 and windows+([#619](https://github.com/haskell/haskell-language-server/pull/619)) by @jneira+- Module Name Plugin: Treat modules starting with lowercase as Main module+([#616](https://github.com/haskell/haskell-language-server/pull/616)) by @konn+- Bump ormolu to 0.1.4.1+([#614](https://github.com/haskell/haskell-language-server/pull/614)) by @AlistairB+- Fix fourmolu plugin inconsistent formatting+([#599](https://github.com/haskell/haskell-language-server/pull/599)) by @zweimach+- Hlint: bring over idea2Message for formatting+([#598](https://github.com/haskell/haskell-language-server/pull/598)) by @alanz+- Makes dictionary argument exclusion logic in Tactic plugin more robust+([#508](https://github.com/haskell/haskell-language-server/pull/508)) by @konn++## 0.6.0++0.6.0 includes two brand new plugins!++- [Hlint Plugin](https://github.com/haskell/haskell-language-server/pull/166): it integrates hlint diagnostics and lets you apply suggestions to fix them.++++- [Module Name Plugin](https://github.com/haskell/haskell-language-server/pull/480): it makes easier create new modules and modify them, suggesting the appropiate module name as a code lens.++++This release also includes many improvements and bug fixes for the tactic plugin (see pull requests authored by @isovector for more details).++We have updated two essential tools used by the ide:++- `implicit-hie`: [to fix a bug](https://github.com/haskell/haskell-language-server/issues/498) present when loading cabal based projects with executables containing `other-modules`++- `ghcide`: the ide uses [the just released version 0.5](https://github.com/haskell/ghcide/blob/master/CHANGELOG.md#050-2020-10-08) with many bug fixes and improvements, including:+ - code action to remove *all* redundant imports+ - improved support for Template Haskell+ - emit desugarer warnings++### Pull requests merged for 0.6.0++- Fix tasty rerun+([#570](https://github.com/haskell/haskell-language-server/pull/570)) by @jneira+- Bump up ghcide submodule to version 0.5.0+([#568](https://github.com/haskell/haskell-language-server/pull/568)) by @jneira+- Refactor tactics to track hypothesis provenance+([#557](https://github.com/haskell/haskell-language-server/pull/557)) by @isovector+- Use bash shell to allow its idioms+([#552](https://github.com/haskell/haskell-language-server/pull/552)) by @jneira+- Ignore flakey tactics test+([#546](https://github.com/haskell/haskell-language-server/pull/546)) by @isovector+- Better scoring metric for deriving safeHead+([#545](https://github.com/haskell/haskell-language-server/pull/545)) by @isovector+- Discover skolems in the hypothesis, not just goal+([#542](https://github.com/haskell/haskell-language-server/pull/542)) by @isovector+- [retrie] Fix code action title+([#538](https://github.com/haskell/haskell-language-server/pull/538)) by @pepeiborra+- Tactics support for using given constraints+([#534](https://github.com/haskell/haskell-language-server/pull/534)) by @isovector+- Add missing tactic subpackage in default stack.yaml+([#529](https://github.com/haskell/haskell-language-server/pull/529)) by @jneira+- Use implicit-hie-0.1.2.0+([#528](https://github.com/haskell/haskell-language-server/pull/528)) by @jneira+- Wait for diagnostics in tactics tests+([#525](https://github.com/haskell/haskell-language-server/pull/525)) by @isovector+- Fix a bug in tactics preventing split of split+([#520](https://github.com/haskell/haskell-language-server/pull/520)) by @isovector+- Use infix notation for destructing and splitting infix data cons+([#519](https://github.com/haskell/haskell-language-server/pull/519)) by @isovector+- Retry the build three times+([#518](https://github.com/haskell/haskell-language-server/pull/518)) by @jneira+- Separate tactics into its own package+([#516](https://github.com/haskell/haskell-language-server/pull/516)) by @isovector+- Add a Troubleshooting section to the README+([#507](https://github.com/haskell/haskell-language-server/pull/507)) by @michaelpj+- Add GitHub Actions CI for testing+([#504](https://github.com/haskell/haskell-language-server/pull/504)) by @bubba+- Fix stack build for ghc-8.8.3 failing on some machines+([#503](https://github.com/haskell/haskell-language-server/pull/503)) by @luntain+- Expand explanation of how to configure HLS+([#497](https://github.com/haskell/haskell-language-server/pull/497)) by @michaelpj+- Module Name Plugin+([#480](https://github.com/haskell/haskell-language-server/pull/480)) by @tittoassini+- Allow hole filling to deal with recursion+([#472](https://github.com/haskell/haskell-language-server/pull/472)) by @isovector+- Restrict editor config to Haskell file, to avoid affecting Makefiles or other tab-based formats+([#442](https://github.com/haskell/haskell-language-server/pull/442)) by @tittoassini+- Hlint plugin using ghc-lib+([#166](https://github.com/haskell/haskell-language-server/pull/166)) by @jneira++## 0.5.1++0.5.1 is a minor bug fix release, mainly fixing an issue with the eval plugin+as well as upgrading the ormolu and stylish-haskell dependencies.++### Pull requests merged for 0.5.1++- Minimal fix for eval regression+([#488](https://github.com/haskell/haskell-language-server/pull/488)) by @pepeiborra+- Bump stylish-haskell to 0.12.2.0+([#482](https://github.com/haskell/haskell-language-server/pull/482)) by @maksbotan+- Improve the emacs instructions a little+([#479](https://github.com/haskell/haskell-language-server/pull/479)) by @michaelpj+- Update README: HLS is no longer in *very* early stage+([#475](https://github.com/haskell/haskell-language-server/pull/475)) by @Anrock+- Tactic plugin: Excludes Dictionary arguments in GADTs in Destruct Tactic+([#474](https://github.com/haskell/haskell-language-server/pull/474)) by @konn+- Update doom emacs install instructions in README+([#470](https://github.com/haskell/haskell-language-server/pull/470)) by @iyefrat+- Add ghc-8.10.2 to circleci+([#464](https://github.com/haskell/haskell-language-server/pull/464)) by @jneira+- Bump ormolu to 0.1.3.0+([#422](https://github.com/haskell/haskell-language-server/pull/422)) by @AlistairB++## 0.5.0++0.5.0 comes with a new tactics plugin which provides case splitting, homomorphic case splitting, and lambda introduction:++++It can even attempt to fully fill a hole!++++The imports lens plugin also learnt a new code action to make all imports explicit:++++There's also plenty of bug fixes, improvements and updates to the underlying tools, including Fourmolu, implicit-hie-cradle and ghcide. [Some of the improvements from ghcide](https://github.com/haskell/ghcide/releases/tag/v0.4.0) include:++- The entire project is typechecked on load+- Reverse dependencies of a module are typechecked upon saving+- Code completion includes local terms+- Import code actions now also suggest open imports+- Documentation on hover shows for symbols defined in the same module++If you're eager to try all this out, haskell-language-server is now also installable via [ghcup](https://www.haskell.org/ghcup/):++```shell+$ ghcup install hls+```++### Pull requests merged for 0.5.0++- Update GHC version 8.12 to 9.0 in README+([#460](https://github.com/haskell/haskell-language-server/pull/460)) by @maralorn+- Update Fourmolu to 0.2+([#455](https://github.com/haskell/haskell-language-server/pull/455)) by @georgefst+- Generate .gz tars of all the binaries for macOS and Linux in GitHub Actions+([#454](https://github.com/haskell/haskell-language-server/pull/454)) by @bubba+- install: create hls hardlinks instead of copies except on Windows+([#451](https://github.com/haskell/haskell-language-server/pull/451)) by @juhp+- wrapper: cd to --cwd earlier+([#448](https://github.com/haskell/haskell-language-server/pull/448)) by @ocharles+- Update README.md+([#446](https://github.com/haskell/haskell-language-server/pull/446)) by @moodmosaic+- Upate Emacs setup notes+([#440](https://github.com/haskell/haskell-language-server/pull/440)) by @gdevanla+- Use ghcide master and prepare hls-plugin-api-0.4.1.0+([#439](https://github.com/haskell/haskell-language-server/pull/439)) by @jneira+- Add a code action to make all imports explicit+([#436](https://github.com/haskell/haskell-language-server/pull/436)) by @pepeiborra+- Add docs on how to choose a formatter+([#432](https://github.com/haskell/haskell-language-server/pull/432)) by @googleson78+- Implement 'Attempt to fill hole' code action+([#431](https://github.com/haskell/haskell-language-server/pull/431)) by @TOTBWF+- Clarify that eval is a lens+([#428](https://github.com/haskell/haskell-language-server/pull/428)) by @Anrock+- Use implicit-hie-cradle-0.2.0.1+([#427](https://github.com/haskell/haskell-language-server/pull/427)) by @jneira+- [retrie] Fix uris in workspace edit+([#424](https://github.com/haskell/haskell-language-server/pull/424)) by @pepeiborra+- Separate paragraphs+([#423](https://github.com/haskell/haskell-language-server/pull/423)) by @jneira+- Include .editorconfig in the contributing section+([#420](https://github.com/haskell/haskell-language-server/pull/420)) by @jneira+- Mention the copy of executables wit ghc version+([#419](https://github.com/haskell/haskell-language-server/pull/419)) by @jneira+- Eval plugin: proper multilined results handling and command-name abbreviations+([#413](https://github.com/haskell/haskell-language-server/pull/413)) by @konn+- Retrie - calculate imports in the command handler+([#408](https://github.com/haskell/haskell-language-server/pull/408)) by @pepeiborra+- Progress reporting for Eval plugin+([#398](https://github.com/haskell/haskell-language-server/pull/398)) by @pepeiborra+- bump ghcide submodule+([#396](https://github.com/haskell/haskell-language-server/pull/396)) by @wz1000+- Fix cradles+([#393](https://github.com/haskell/haskell-language-server/pull/393)) by @pepeiborra+- Case splitting and lambda introduction+([#391](https://github.com/haskell/haskell-language-server/pull/391)) by @isovector+- Use stale data in explicit imports lens+([#383](https://github.com/haskell/haskell-language-server/pull/383)) by @pepeiborra+- Create hls-plugin-api and move plugins to exe+([#379](https://github.com/haskell/haskell-language-server/pull/379)) by @jneira+- Rebase on ghcide HEAD+([#378](https://github.com/haskell/haskell-language-server/pull/378)) by @pepeiborra+- README clarify how exactly to use code evaluation+([#377](https://github.com/haskell/haskell-language-server/pull/377)) by @DunetsNM+- Revise README.md+([#374](https://github.com/haskell/haskell-language-server/pull/374)) by @gihyeonsung++## 0.4.0++0.4.0 introduces the import lens plugin, which can convert your import statements into qualified imports, or into an explicit import list:++++The eval plugin has also learnt two new commands, `:type` and `:kind`:++```haskell+{-# LANGUAGE TypeApplications #-}+foo :: Show a => a -> String+foo = show++-- >>> :type foo @Int+-- foo @Int :: Int -> String++-- >>> :type +v foo @Int+-- foo @Int :: Show Int => Int -> String+```++```haskell+-- >>> type N = 1+-- >>> type M = 40+-- >>> :kind N + M + 1+-- N + M + 1 :: Nat++-- >>> type N = 1+-- >>> type M = 40+-- >>> :kind N + M + 1+-- N + M + 1 :: Nat+```++There is now also support for GHC 8.10.2, and a new `haskell-language-server --probe-tools` command to help debug what version of each tool HLS is using.++```shell+$ haskell-language-server --probe-tools+haskell-language-server version: 0.3.0.0 (GHC: 8.10.1) (PATH: /Users/luke/.cabal/store/ghc-8.10.1/hskll-lngg-srvr-0.3.0.0-7c6d48c3/bin/haskell-language-server)+Tool versions found on the $PATH+cabal: 3.2.0.0+stack: 2.3.3+ghc: 8.10.2+```++### Pull requests merged for 0.4.0++- Bring over a [tutorial about how to add hls plugins](https://github.com/pepeiborra/hls-tutorial)+([#372](https://github.com/haskell/haskell-language-server/pull/372)) by @bubba+- Update the ghcide upstream to be in haskell/ghcide+([#370](https://github.com/haskell/haskell-language-server/pull/370)) by @alanz+- Add ISSUE_TEMPLATE for github+([#305](https://github.com/haskell/haskell-language-server/pull/305)) by @fendor+- Add use-package to the list of emacs packages+([#343](https://github.com/haskell/haskell-language-server/pull/343)) by @rgleichman+- Implements `:type [+v/+d]` in Eval Plugin+([#361](https://github.com/haskell/haskell-language-server/pull/361)) by @konn+- Bump bounds of hie-bios to 0.7.0+([#357](https://github.com/haskell/haskell-language-server/pull/357)) by @maralorn+- Fix ImportLens plugin to work with GHC 8.10+([#356](https://github.com/haskell/haskell-language-server/pull/356)) by @Ailrun+- Add single file rewrites and ignore unknown files+([#321](https://github.com/haskell/haskell-language-server/pull/321)) by @pepeiborra+- Do not suggest explicit import lists for qualified imports+([#354](https://github.com/haskell/haskell-language-server/pull/354)) by @expipiplus1+- Explicit imports lens (as seen on Twitter)+([#310](https://github.com/haskell/haskell-language-server/pull/310)) by @pepeiborra+- Adds `:kind` and `:kind!` commands to Eval Plugin+([#345](https://github.com/haskell/haskell-language-server/pull/345)) by @konn+- tech(nix): update niv and remove allowbroken+([#350](https://github.com/haskell/haskell-language-server/pull/350)) by @willbush+- Update VS Code Haskell URL/repo+([#338](https://github.com/haskell/haskell-language-server/pull/338)) by @Sir4ur0n+- doc(hack): Add explanation to hack and test HLS+([#329](https://github.com/haskell/haskell-language-server/pull/329)) by @Sir4ur0n+- Apply the module pragmas for evaluation+([#322](https://github.com/haskell/haskell-language-server/pull/322)) by @pepeiborra+- Copy working stack-8.6.5.yaml to stack.yaml+([#332](https://github.com/haskell/haskell-language-server/pull/332)) by @jneira+- tech(nix): Allow broken as retrie is marked as broken+([#331](https://github.com/haskell/haskell-language-server/pull/331)) by @Sir4ur0n+- feat(git): Add install/hie.yaml to gitignore+([#328](https://github.com/haskell/haskell-language-server/pull/328)) by @Sir4ur0n+- Replace wrong occurrences of "engine" by "server"+([#319](https://github.com/haskell/haskell-language-server/pull/319)) by @tchoutri+- Simplify coc.nvim instructions+([#315](https://github.com/haskell/haskell-language-server/pull/315)) by @oblitum+- Coc config file requires a {} nesting everything+([#317](https://github.com/haskell/haskell-language-server/pull/317)) by @hyiltiz+- Restrict opentelemetry version for stack builds+([#312](https://github.com/haskell/haskell-language-server/pull/312)) by @jneira+- Add support for ghc-8.10.2+([#308](https://github.com/haskell/haskell-language-server/pull/308)) by @jneira+- Return nothing if tool is not on the PATH+([#309](https://github.com/haskell/haskell-language-server/pull/309)) by @fendor+- Probe tools cli+([#306](https://github.com/haskell/haskell-language-server/pull/306)) by @fendor+- Add fourmolu plugin (attempt 2) and add Brittany for ghc-8.10.1+([#264](https://github.com/haskell/haskell-language-server/pull/264)) by @georgefst++## 0.3.0++0.3.0 comes with two new plugins, retrie and fourmolu, provides binaries for+GHC 8.8.4, and comes with a host of bug fixes.++The retrie plugin supports RULES, functions and type synonyms which can be+accessed through contextual code actions.++Fourmolu can be used to format your code by setting the+`haskell.formattingProvider` field in your LSP configuration to++```json+{+ "haskell": {+ "formattingProvider": "fourmolu"+ }+}+```++The Brittany formatter is now also available on GHC 8.10.1.++### Pull requests merged++- Fix haddock parse error in install.hs+([#255](https://github.com/haskell/haskell-language-server/pull/255)) by @georgefst+- Ormolu flags+([#246](https://github.com/haskell/haskell-language-server/pull/246)) by @pepeiborra+- Ormolu fix+([#257](https://github.com/haskell/haskell-language-server/pull/257)) by @sureyeaah+- Remove redundant CircleCI steps+([#259](https://github.com/haskell/haskell-language-server/pull/259)) by @bubba+- Slow down Tasty by limiting it to -j1+([#261](https://github.com/haskell/haskell-language-server/pull/261)) by @bubba+- Remove hspec-expectations+([#260](https://github.com/haskell/haskell-language-server/pull/260)) by @bubba+- Remove a redundant caching step+([#262](https://github.com/haskell/haskell-language-server/pull/262)) by @Ailrun+- add hie.yaml to coc configuration+([#267](https://github.com/haskell/haskell-language-server/pull/267)) by @sureyeaah+- Initial Retrie plugin+([#266](https://github.com/haskell/haskell-language-server/pull/266)) by @pepeiborra+- Add exe extension to win executables+([#284](https://github.com/haskell/haskell-language-server/pull/284)) by @jneira+- Use wz1000/hls-3 ghcide branch+([#275](https://github.com/haskell/haskell-language-server/pull/275)) by @alanz+- Fix rename capability being declared+([#285](https://github.com/haskell/haskell-language-server/pull/285)) by @bubba+- Add CI job for 8.8.4+([#287](https://github.com/haskell/haskell-language-server/pull/287)) by @bubba+- Make the AGPL flag manual in cabal+([#250](https://github.com/haskell/haskell-language-server/pull/250)) by @fendor+- Bring in doc URL fix for Windows+([#289](https://github.com/haskell/haskell-language-server/pull/289)) by @bubba+- Bring in fix for libm on Linux static binaries+([#293](https://github.com/haskell/haskell-language-server/pull/293)) by @bubba+- Add fourmolu plugin (attempt 2) and add Brittany for ghc-8.10.1+([#264](https://github.com/haskell/haskell-language-server/pull/264)) by @georgefst+- Trying new hls-3 branch+([#300](https://github.com/haskell/haskell-language-server/pull/300)) by @alanz++## 0.2.2++This changes the configuration section from "languageServerHaskell" to "haskell"+to align it with vscode-haskell-1.0.0. Whilst the old section is still+supported for now, you should update your LSP configuration (which varies per+client) from++```json+{+ "languageServerHaskell": {+ "formattingProvider": "stylish-haskell"+ }+}+```++to++```json+{+ "haskell": {+ "formattingProvider": "stylish-haskell"+ }+}+```++### Pull requests merged for 0.2.2++- Mention docs on hover feature in README+([#209](https://github.com/haskell/haskell-language-server/pull/209)) by @georgefst+- Add static binaries for ghc-8.8.4+([#224](https://github.com/haskell/haskell-language-server/pull/224)) by @bubba+- Rename the configuration section from languageServerHaskell => haskell+([#227](https://github.com/haskell/haskell-language-server/pull/227)) by @bubba+- Use -haddock for cabal and stack+([#214](https://github.com/haskell/haskell-language-server/pull/214)) by @jneira+- slightly better shell.nix for local development+([#235](https://github.com/haskell/haskell-language-server/pull/235)) by @pepeiborra+- Shell nix further steps+([#240](https://github.com/haskell/haskell-language-server/pull/240)) by @pepeiborra+- Add numeric-version option for wrapper and server+([#241](https://github.com/haskell/haskell-language-server/pull/241)) by @fendor+- Accept the legacy "languageServerHaskell" config name+([#243](https://github.com/haskell/haskell-language-server/pull/243)) by @bubba+- Fix for Eval plugin: Error from tests not reported+([#244](https://github.com/haskell/haskell-language-server/pull/244)) by @tittoassini+- Rename binaries before uploading+([#248](https://github.com/haskell/haskell-language-server/pull/248)) by @bubba++## 0.2.1++This release includes a new eval plugin that allows Haddock code examples to be+evaluated through a code lens. For example, the code below will now offer to+evaluate `intercalate " " example`, and will insert the output in the line+below.++```haskell+example :: [String]+example = ["This is an example", "of", "interactive", "evaluation"]++-- >>> intercalate " " example+-- "This is an example of interactive evaluation"+--+```++This is also the first release to have binaries distributed alongside it. Some+behind the scene changes include the GHC library directory now being obtained on+the fly, so either `ghc`, `cabal` or `stack` will need to be present on your+PATH depending on your project. See `docs/releases.md` for more information. If+you find any issues with this, please let us know!++### Pull requests merged for 0.2.1++- Bump ormolu to 0.1.2.0+([#189](https://github.com/haskell/haskell-language-server/pull/189)) by @AlistairB+- Remove dependency on Cabal+([#195](https://github.com/haskell/haskell-language-server/pull/195)) by @bubba+- Fix extraneous extra-dep in stack-8.6.4.yaml+([#199](https://github.com/haskell/haskell-language-server/pull/199)) by @bubba+- Fix install script stack targets+([#203](https://github.com/haskell/haskell-language-server/pull/203)) by @jneira+- Add support for ghc-8.8.4+([#206](https://github.com/haskell/haskell-language-server/pull/206)) by @jneira+- Simple Eval plugin+([#191](https://github.com/haskell/haskell-language-server/pull/191)) by @pepeiborra+- Distributable binaries+([#165](https://github.com/haskell/haskell-language-server/pull/165)) by @bubba++## 0.2++- Use cabal-plan from Hackage+([#185](https://github.com/haskell/haskell-language-server/pull/185)) by @georgefst+- Bump ghcide to wz1000 hls-2 branch+([#184](https://github.com/haskell/haskell-language-server/pull/184)) by @alanz+- doc(preprocessor): Document the preprocessor limitation+([#177](https://github.com/haskell/haskell-language-server/pull/177)) by @Sir4ur0n+- Use shell.nix from Haskell-IDE-Engine+([#169](https://github.com/haskell/haskell-language-server/pull/169)) by @fendor+- Remove last occurrences of shake.yaml+([#163](https://github.com/haskell/haskell-language-server/pull/163)) by @fendor+- Use an unique install/stack.yaml+([#154](https://github.com/haskell/haskell-language-server/pull/154)) by @jneira+- Introduce golden testing+([#152](https://github.com/haskell/haskell-language-server/pull/152)) by @Ailrun+- Revert "Use bullet as separator instead of HR"+([#150](https://github.com/haskell/haskell-language-server/pull/150)) by @alanz+- feat(hie-bios): Multi-cradle, ignore directories+([#147](https://github.com/haskell/haskell-language-server/pull/147)) by @Sir4ur0n+- [Plugin] stylish-haskell formatter+([#146](https://github.com/haskell/haskell-language-server/pull/146)) by @Ailrun+- Separate ghcide tests and disable them for now+([#137](https://github.com/haskell/haskell-language-server/pull/137)) by @jneira+- Convert private lib in common stanza+([#136](https://github.com/haskell/haskell-language-server/pull/136)) by @jneira+- Add zlibc to readme+([#134](https://github.com/haskell/haskell-language-server/pull/134)) by @Sir4ur0n+- Complete editor integrations+([#132](https://github.com/haskell/haskell-language-server/pull/132)) by @jneira+- Remove inexistent component from hie.yaml.stack+([#131](https://github.com/haskell/haskell-language-server/pull/131)) by @jneira+- Bump to new mpickering/ghcide+([#130](https://github.com/haskell/haskell-language-server/pull/130)) by @alanz+- Update ghc-lib-parser version+([#129](https://github.com/haskell/haskell-language-server/pull/129)) by @jneira+- Remove redundant import+([#128](https://github.com/haskell/haskell-language-server/pull/128)) by @bubba+- Default the number of Shake threads to 0 (automatic)+([#127](https://github.com/haskell/haskell-language-server/pull/127)) by @bubba+- Added kakoune integration instructions+([#125](https://github.com/haskell/haskell-language-server/pull/125)) by @414owen+- Fix install script dev target+([#124](https://github.com/haskell/haskell-language-server/pull/124)) by @jneira+- Add plugin support for Rename providers+([#123](https://github.com/haskell/haskell-language-server/pull/123)) by @pepeiborra+- Add jobs for stack and cabal using ghc-8.10.1+([#120](https://github.com/haskell/haskell-language-server/pull/120)) by @jneira+- Add lower bound to tasty-ant-xml+([#119](https://github.com/haskell/haskell-language-server/pull/119)) by @jneira+- Fix build using brittany revision+([#117](https://github.com/haskell/haskell-language-server/pull/117)) by @jneira+- Use floskell released version 0.10.3+([#116](https://github.com/haskell/haskell-language-server/pull/116)) by @jneira+- Add emacs/doom-emacs integration sub-section+([#115](https://github.com/haskell/haskell-language-server/pull/115)) by @yuanw+- Port hie README partially+([#112](https://github.com/haskell/haskell-language-server/pull/112)) by @jneira+- Use cabal-helper-1.1, add stack-8.10.1.yaml and unify cabal.project's+([#108](https://github.com/haskell/haskell-language-server/pull/108)) by @jneira+- [#87] Fix completion via ghcide's `getCompletionsLSP`+([#107](https://github.com/haskell/haskell-language-server/pull/107)) by @korayal+- Create specific project file for ghc-8.10.+([#106](https://github.com/haskell/haskell-language-server/pull/106)) by @jneira+- Issue 5 - Move HIE Tests and convert to Tasty+([#105](https://github.com/haskell/haskell-language-server/pull/105)) by @jeffwindsor+- Hls update latest hie bios+([#100](https://github.com/haskell/haskell-language-server/pull/100)) by @fendor+- Update extra-deps to use latest fork version of shake+([#98](https://github.com/haskell/haskell-language-server/pull/98)) by @fendor+- Activate typechecking in non-lsp mode+([#95](https://github.com/haskell/haskell-language-server/pull/95)) by @jneira+- Fix haddock parsing errors+([#92](https://github.com/haskell/haskell-language-server/pull/92)) by @jneira+- Update for haskell-lsp 0.22+([#89](https://github.com/haskell/haskell-language-server/pull/89)) by @alanz+- Get building with ghc-8.10+([#83](https://github.com/haskell/haskell-language-server/pull/83)) by @bubba++## 0.1++### In this version++- cabal to 2020-05-02T10:11:15Z+- stack-8.8.3 to lts-15.10+- stack to nightly-2020-05-01++### Changes++This is the initial version, so too many to list individually.++The key point is that is now supports multi-component cradles, and has been in+daily use by the developers for some time.++It still does not have feature parity with `haskell-ide-engine`, but it is+currently useful.
@@ -1,201 +1,201 @@- Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + Apache License+ Version 2.0, January 2004+ http://www.apache.org/licenses/++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++ 1. Definitions.++ "License" shall mean the terms and conditions for use, reproduction,+ and distribution as defined by Sections 1 through 9 of this document.++ "Licensor" shall mean the copyright owner or entity authorized by+ the copyright owner that is granting the License.++ "Legal Entity" shall mean the union of the acting entity and all+ other entities that control, are controlled by, or are under common+ control with that entity. For the purposes of this definition,+ "control" means (i) the power, direct or indirect, to cause the+ direction or management of such entity, whether by contract or+ otherwise, or (ii) ownership of fifty percent (50%) or more of the+ outstanding shares, or (iii) beneficial ownership of such entity.++ "You" (or "Your") shall mean an individual or Legal Entity+ exercising permissions granted by this License.++ "Source" form shall mean the preferred form for making modifications,+ including but not limited to software source code, documentation+ source, and configuration files.++ "Object" form shall mean any form resulting from mechanical+ transformation or translation of a Source form, including but+ not limited to compiled object code, generated documentation,+ and conversions to other media types.++ "Work" shall mean the work of authorship, whether in Source or+ Object form, made available under the License, as indicated by a+ copyright notice that is included in or attached to the work+ (an example is provided in the Appendix below).++ "Derivative Works" shall mean any work, whether in Source or Object+ form, that is based on (or derived from) the Work and for which the+ editorial revisions, annotations, elaborations, or other modifications+ represent, as a whole, an original work of authorship. For the purposes+ of this License, Derivative Works shall not include works that remain+ separable from, or merely link (or bind by name) to the interfaces of,+ the Work and Derivative Works thereof.++ "Contribution" shall mean any work of authorship, including+ the original version of the Work and any modifications or additions+ to that Work or Derivative Works thereof, that is intentionally+ submitted to Licensor for inclusion in the Work by the copyright owner+ or by an individual or Legal Entity authorized to submit on behalf of+ the copyright owner. For the purposes of this definition, "submitted"+ means any form of electronic, verbal, or written communication sent+ to the Licensor or its representatives, including but not limited to+ communication on electronic mailing lists, source code control systems,+ and issue tracking systems that are managed by, or on behalf of, the+ Licensor for the purpose of discussing and improving the Work, but+ excluding communication that is conspicuously marked or otherwise+ designated in writing by the copyright owner as "Not a Contribution."++ "Contributor" shall mean Licensor and any individual or Legal Entity+ on behalf of whom a Contribution has been received by Licensor and+ subsequently incorporated within the Work.++ 2. Grant of Copyright License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ copyright license to reproduce, prepare Derivative Works of,+ publicly display, publicly perform, sublicense, and distribute the+ Work and such Derivative Works in Source or Object form.++ 3. Grant of Patent License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ (except as stated in this section) patent license to make, have made,+ use, offer to sell, sell, import, and otherwise transfer the Work,+ where such license applies only to those patent claims licensable+ by such Contributor that are necessarily infringed by their+ Contribution(s) alone or by combination of their Contribution(s)+ with the Work to which such Contribution(s) was submitted. If You+ institute patent litigation against any entity (including a+ cross-claim or counterclaim in a lawsuit) alleging that the Work+ or a Contribution incorporated within the Work constitutes direct+ or contributory patent infringement, then any patent licenses+ granted to You under this License for that Work shall terminate+ as of the date such litigation is filed.++ 4. Redistribution. You may reproduce and distribute copies of the+ Work or Derivative Works thereof in any medium, with or without+ modifications, and in Source or Object form, provided that You+ meet the following conditions:++ (a) You must give any other recipients of the Work or+ Derivative Works a copy of this License; and++ (b) You must cause any modified files to carry prominent notices+ stating that You changed the files; and++ (c) You must retain, in the Source form of any Derivative Works+ that You distribute, all copyright, patent, trademark, and+ attribution notices from the Source form of the Work,+ excluding those notices that do not pertain to any part of+ the Derivative Works; and++ (d) If the Work includes a "NOTICE" text file as part of its+ distribution, then any Derivative Works that You distribute must+ include a readable copy of the attribution notices contained+ within such NOTICE file, excluding those notices that do not+ pertain to any part of the Derivative Works, in at least one+ of the following places: within a NOTICE text file distributed+ as part of the Derivative Works; within the Source form or+ documentation, if provided along with the Derivative Works; or,+ within a display generated by the Derivative Works, if and+ wherever such third-party notices normally appear. The contents+ of the NOTICE file are for informational purposes only and+ do not modify the License. You may add Your own attribution+ notices within Derivative Works that You distribute, alongside+ or as an addendum to the NOTICE text from the Work, provided+ that such additional attribution notices cannot be construed+ as modifying the License.++ You may add Your own copyright statement to Your modifications and+ may provide additional or different license terms and conditions+ for use, reproduction, or distribution of Your modifications, or+ for any such Derivative Works as a whole, provided Your use,+ reproduction, and distribution of the Work otherwise complies with+ the conditions stated in this License.++ 5. Submission of Contributions. Unless You explicitly state otherwise,+ any Contribution intentionally submitted for inclusion in the Work+ by You to the Licensor shall be under the terms and conditions of+ this License, without any additional terms or conditions.+ Notwithstanding the above, nothing herein shall supersede or modify+ the terms of any separate license agreement you may have executed+ with Licensor regarding such Contributions.++ 6. Trademarks. This License does not grant permission to use the trade+ names, trademarks, service marks, or product names of the Licensor,+ except as required for reasonable and customary use in describing the+ origin of the Work and reproducing the content of the NOTICE file.++ 7. Disclaimer of Warranty. Unless required by applicable law or+ agreed to in writing, Licensor provides the Work (and each+ Contributor provides its Contributions) on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+ implied, including, without limitation, any warranties or conditions+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+ PARTICULAR PURPOSE. You are solely responsible for determining the+ appropriateness of using or redistributing the Work and assume any+ risks associated with Your exercise of permissions under this License.++ 8. Limitation of Liability. In no event and under no legal theory,+ whether in tort (including negligence), contract, or otherwise,+ unless required by applicable law (such as deliberate and grossly+ negligent acts) or agreed to in writing, shall any Contributor be+ liable to You for damages, including any direct, indirect, special,+ incidental, or consequential damages of any character arising as a+ result of this License or out of the use or inability to use the+ Work (including but not limited to damages for loss of goodwill,+ work stoppage, computer failure or malfunction, or any and all+ other commercial damages or losses), even if such Contributor+ has been advised of the possibility of such damages.++ 9. Accepting Warranty or Additional Liability. While redistributing+ the Work or Derivative Works thereof, You may choose to offer,+ and charge a fee for, acceptance of support, warranty, indemnity,+ or other liability obligations and/or rights consistent with this+ License. However, in accepting such obligations, You may act only+ on Your own behalf and on Your sole responsibility, not on behalf+ of any other Contributor, and only if You agree to indemnify,+ defend, and hold each Contributor harmless for any liability+ incurred by, or claims asserted against, such Contributor by reason+ of your accepting any such warranty or additional liability.++ END OF TERMS AND CONDITIONS++ APPENDIX: How to apply the Apache License to your work.++ To apply the Apache License to your work, attach the following+ boilerplate notice, with the fields enclosed by brackets "[]"+ replaced with your own identifying information. (Don't include+ the brackets!) The text should be enclosed in the appropriate+ comment syntax for the file format. We also recommend that a+ file or class name and description of purpose be included on the+ same "printed page" as the copyright notice for easier+ identification within third-party archives.++ Copyright [yyyy] [name of copyright owner]++ Licensed under the Apache License, Version 2.0 (the "License");+ you may not use this file except in compliance with the License.+ You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++ Unless required by applicable law or agreed to in writing, software+ distributed under the License is distributed on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ See the License for the specific language governing permissions and+ limitations under the License.
@@ -1,767 +1,816 @@-# haskell-language-server - -![haskell-language-server][logo] - -[![Hackage][badge-hackage]][hackage] -[![License Apache 2.0][badge-license]][license] -[![CircleCI][badge-circleci]][circleci] - - - -[logo]: ./docs/logos/logo-256.png -[badge-license]: https://img.shields.io/badge/license-Apache2-green.svg?dummy -[license]: https://github.com/haskell/haskell-language-server/blob/master/LICENSE -[badge-circleci]: https://img.shields.io/circleci/project/github/haskell/haskell-language-server/master.svg -[circleci]: https://circleci.com/gh/haskell/haskell-language-server/ -[badge-hackage]: https://img.shields.io/hackage/v/haskell-language-server.svg?logo=haskell -[hackage]: https://hackage.haskell.org/package/haskell-language-server - -Integration point for [ghcide](https://github.com/haskell/ghcide) and [haskell-ide-engine](https://github.com/haskell/haskell-ide-engine). One IDE to rule -them all. Read the [project's -background](https://neilmitchell.blogspot.com/2020/01/one-haskell-ide-to-rule-them-all.html). - -- [Haskell Language Server (HLS)](#haskell-language-server) - - [Features](#features) - - [Installation](#installation) - - [Prerequisites](#prerequisites) - - [ghcup](#ghcup) - - [Visual Studio Code](#visual-studio-code) - - [Pre-built binaries](#pre-built-binaries) - - [Installation from source](#installation-from-source) - - [Common pre-requirements](#common-pre-requirements) - - [Linux-specific pre-requirements](#linux-specific-pre-requirements) - - [Windows-specific pre-requirements](#windows-specific-pre-requirements) - - [Download the source code](#download-the-source-code) - - [Building](#building) - - [Install via cabal](#install-via-cabal) - - [Install specific GHC Version](#install-specific-ghc-version) - - [Installation from Hackage](#installation-from-hackage) - - [Configuring haskell-language-server](#configuring-haskell-language-server) - - [Configuring your project build](#configuring-your-project-build) - - [Configuring your editor](#configuring-your-editor) - - [VS Code](#using-haskell-language-server-with-vs-code) - - [Sublime Text](#using-haskell-language-server-with-sublime-text) - - [Vim or Neovim](#using-haskell-language-server-with-vim-or-neovim) - - [Atom](#using-haskell-language-server-with-atom) - - [Emacs](#using-haskell-language-server-with-emacs) - - [Kakoune](#using-haskell-language-server-with-kakoune) - - [Known limitations](#known-limitations) - - [Preprocessor](#preprocessor) - - [Troubleshooting](#troubleshooting) - - [Contributing](#contributing) - - [Building haskell-language-server](#building-haskell-language-server) - - [Using Cabal](#using-cabal) - - [Using Stack](#using-stack) - - [Introduction tutorial](#instructions-tutorial) - - [Test your hacked HLS in your editor](#test-your-hacked-hls-in-your-editor) - -## Features - -- Code evaluation codelens ([Tutorial](plugins/hls-eval-plugin/README.md)): - -  - -- Type information and documentation on hover. Note that currently, in order for docs to be displayed for dependencies, they must have been built with GHC's `-haddock` flag: - - - For cabal: - - Add to your global config file (e.g. `~/.cabal/config`): - ``` - program-default-options - ghc-options: -haddock - ``` - - Or, for a single project, run `cabal configure --ghc-options=-haddock` - - - For stack, add to global `$STACK_ROOT\config.yaml`, or project's `stack.yaml`: - ``` - ghc-options: - "$everything": -haddock - ``` - - This will cause compilation errors if a dependency contains invalid Haddock markup, though from GHC version 9.0, [these will be demoted to warnings](https://gitlab.haskell.org/ghc/ghc/-/merge_requests/2377). - - - Integration with [retrie](https://hackage.haskell.org/package/retrie) - -  - - - Code lenses for explicit import lists - -  - - - Many more (TBD) - -## Installation - -### Prerequisites - -- For standalone `.hs`/`.lhs` files, [ghc](https://www.haskell.org/ghc/) must be installed and on the PATH. The easiest way to install it is with [ghcup](https://www.haskell.org/ghcup/) or [Chocolatey](https://www.haskell.org/platform/windows.html) on Windows. -- For Cabal based projects, both ghc and [cabal-install](https://www.haskell.org/cabal/) must be installed and on the PATH. It can also be installed with [ghcup](https://www.haskell.org/ghcup/) or [Chocolatey](https://www.haskell.org/platform/windows.html) on Windows. -- For Stack based projects, [stack](http://haskellstack.org) must be installed and on the PATH. - -### ghcup - -If you are using [`ghcup`](https://www.haskell.org/ghcup/) to manage your installations, you can install the latest version of `haskell-language-server` with -``` -ghcup install hls -``` - -### Visual Studio Code - -If you are using Visual Studio Code, the [Haskell extension](https://marketplace.visualstudio.com/items?itemName=haskell.haskell) will automatically download and install `haskell-language-server` for you. - -### Pre-built binaries - -There are pre-built binaries available from the [releases page](https://github.com/haskell/haskell-language-server/releases) for Linux, Windows and macOS. -To install, download the `haskell-language-server-wrapper` executable for your platform as well as any `haskell-language-server` executables for the GHC versions you plan on working with, and either put them on your PATH or point your client to them. - -### Installation from source - -#### Common pre-requirements - -- `stack` or `cabal` must be in your PATH - - You need stack version >= 2.1.1 or cabal >= 2.4.0.0 -- `git` must be in your PATH -- The directory where `stack`or `cabal` put the binaries must be in you PATH: - - For stack you can get it with `stack path --local-bin` - - For cabal it is by default `$HOME/.cabal/bin` in linux and `%APPDATA%\cabal\bin` in windows. - -Tip: you can quickly check if some command is in your path by running the command. -If you receive some meaningful output instead of "command not found"-like message -then it means you have the command in PATH. - -#### Linux-specific pre-requirements - -On Linux you will need install a couple of extra libraries: -- [Unicode (ICU)](http://site.icu-project.org/) -- [NCURSES](https://www.gnu.org/software/ncurses/) -- [Zlib](https://zlib.net/) - -**Debian 9/Ubuntu 18.04 or earlier**: - -```bash -sudo apt install libicu-dev libtinfo-dev libgmp-dev zlib1g-dev -``` - -**Debian 10/Ubuntu 18.10 or later**: - -```bash -sudo apt install libicu-dev libncurses-dev libgmp-dev zlib1g-dev -``` - -**Fedora**: - -```bash -sudo dnf install libicu-devel ncurses-devel zlib-devel -``` - -#### Windows-specific pre-requirements - -In order to avoid problems with long paths on Windows you can do either one of the following: - -1. Clone the `haskell-language-server` to a short path, for example the root of your logical drive (e.g. to - `C:\hls`). Even if you choose `C:\haskell-language-server` you could hit the problem. If this doesn't work or you want to use a longer path, try the second option. - -2. If the `Local Group Policy Editor` is available on your system, go to: `Local Computer Policy -> Computer Configuration -> Administrative Templates -> System -> Filesystem` set `Enable Win32 long paths` to `Enabled`. If you don't have the policy editor you can use regedit by using the following instructions [here](https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#enable-long-paths-in-windows-10-version-1607-and-later). You also need to configure git to allow longer paths by using unicode paths. To set this for all your git repositories use `git config --system core.longpaths true` (you probably need an administrative shell for this) or for just this one repository use `git config core.longpaths true`. - -In addition make sure `haskell-language-server.exe` is not running by closing your editor, otherwise in case of an upgrade the executable can not be installed. - -#### Download the source code - -```bash -git clone https://github.com/haskell/haskell-language-server --recurse-submodules -cd haskell-language-server -``` - -#### Building - -Note, on first invocation of the build script with stack, a GHC is being installed for execution. -The GHC used for the `install.hs` can be adjusted in `./install/stack.yaml` by using a different resolver. - -Available commands can be seen with: - -```bash -stack ./install.hs help -``` - -Remember, this will take time to download a Stackage-LTS and an appropriate GHC for build -haskell-language-server the first time. - -##### Install via cabal - -The install-script can be invoked via `cabal` instead of `stack` with the command - -```bash -cabal v2-run ./install.hs --project-file install/shake.project <target> -``` - -or using the existing alias script - -```bash -./cabal-hls-install <target> -``` - -Running the script with cabal on windows requires a cabal version greater or equal to `3.0.0.0`. - -For brevity, only the `stack`-based commands are presented in the following sections. - -##### Install specific GHC Version - -The script will install the executables `haskell-language-server-wrapper` and `haskell-language-server`. - -It will copy the latter appending the used ghc version, needed by the wrapper to choose the suitable version -for the project at hand. - -So installing the executables directly with `stack install` or `cabal v2-install` may not be enough -for it to work properly. - -Install haskell-language-server for the latest available and supported GHC version (and hoogle docs): - -```bash -stack ./install.hs hls -``` - -Install haskell-language-server for a specific GHC version (and hoogle docs): - -```bash -stack ./install.hs hls-8.8.3 -``` - -`hls-8.8.3` target will build the project and install `haskell-language-server-wrapper`, -`haskell-language-server`, `haskell-language-server-8.8.3` and `haskell-language-server-8.8` -executables. - -The Haskell Language Server can also be built with `cabal v2-build` instead of `stack build`. -This has the advantage that you can decide how the GHC versions have been installed. -To see what GHC versions are available, the command `cabal-hls-install ghcs` can be used. -It will list all *supported* GHC versions that are on the path for build with their respective installation directory. -If you think, this list is incomplete, you can try to modify the PATH variable, such that the executables can be found. -Note, that the targets `hls` and `data` depend on the found GHC versions. - -An example output is: - -```bash -> ./cabal-hls-install ghcs -****************************************************************** -Found the following GHC paths: -ghc-8.6.5: /opt/bin/ghc-8.6.5 -ghc-8.8.3: /opt/bin/ghc-8.8.3 - -****************************************************************** -``` - -If your desired ghc has been found, you use it to install haskell-language-server. - -```bash -./cabal-hls-install hls-8.6.5 -``` - -### Installation from Hackage - -Direct installation from Hackage, while possible via `cabal install haskell-language-server`, is not recommended for most people. -Said command builds the `haskell-language-server` binary and installs it in the default Cabal binaries folder, -but the binary will only work with projects that use the same GHC version that built it. - -The package can be found here on Hackage: https://hackage.haskell.org/package/haskell-language-server - -## Configuring `haskell-language-server` - -Language servers like `haskell-language-server` expose most of their configuration via the client (i.e. the editor). -That means that the way in which you configure the settings will depend on the client. - -Most clients (editors) already have an opinion about how settings should be configured! -For example, in VS Code you use the graphical Settings tab or `settings.json`, whereas in Emacs you use customization variables. -In the [editor configuration section](#configuring-your-editor) we give some pointers for popular editors, but you should consult the documentation for your specific editor if you have trouble. - -However, we can say some high-level things about the kinds of configuration `haskell-language-server` uses, and how to use them. -This can sound a bit confusing, but ultimately the client should present you with these options in a user-friendly way that makes sense for that editor. - -### Generic server options - -The LSP protocol is designed to support many useful server configuration options generically. -These are sent to the server by the client, and can be controlled without reference to a specific language. - -For example, there are protocol methods for highlighting matching identifiers throughout a document. -This is a capability which any server can implement, so the client can decide generically whether to ask the server to do it or not. -So your editor can provide a setting to turn this on or off globally, for any language server you might use. - -Settings like this are typically provided by the generic LSP client support for your editor, for example in Emacs by `lsp-mode`. - -### Generic editor options - -Your editor may provide some settings that affect how the information from the language server is used. -For example, whether popups are shown, or whether code lenses appear by default. - -Settings like this are typically provided by the generic LSP client support for your editor, for example in Emacs by `lsp-mode`. - -### Language-specific server options - -A specific language server can also have its own configuration options. -These are still sent to the server by the client, but they can only be controlled by a specific client that knows about those options. - -For example, `haskell-language-server` allows you to choose the formatting provider which will be used for formatting Haskell source. -This option obviously would not make sense for language servers for other languages, or even for other Haskell language servers (which need not even support formatting). - -Here is a list of the additional settings currently supported by `haskell-language-server`, along with their setting key (you may not need to know this) and default: -- Formatting provider (`haskell.formattingProvider`, default `ormolu`): what formatter to use; one of `floskell`, `ormolu`, `fourmolu`, `stylish-haskell`, or `brittany` (if compiled with AGPL) -- Format on imports (`haskell.formatOnImportOn`, default true): whether to format after adding an import -- Maximum number of problems to report (`haskell.maxNumberOfProblems`, default 100): the maximum number of problems the server will send to the client -- Diagnostics on change (`haskell.diagnosticsOnChange`, default true): (currently unused) -- Completion snippets (`haskell.completionSnippetsOn`, default true): whether to support completion snippets -- Liquid Haskell (`haskell.liquidOn`, default false): whether to enable Liquid Haskell support (currently unused until the Liquid Haskell support is functional again) -- Hlint (`haskell.hlintOn`, default true): whether to enable Hlint support -- Max completions (`haskell.maxCompletions`, default 40): maximum number of completions sent to the LSP client. - -Settings like this are typically provided by the language-specific LSP client support for your editor, for example in Emacs by `lsp-haskell`. - -### Client options - -A particular client might also have some options of its own, for example to control how the server executable is started. - -Settings like this are typically be provided by the language-specific LSP client support for your editor, for example in Emacs by `lsp-haskell`. - -## Configuring your project build - -`haskell-language-server` has to compile your project in order to give you diagnostics, which means that it needs to know how to do so. -This is handled by the [`hie-bios`](https://github.com/mpickering/hie-bios) project. - -**For a full explanation of how `hie-bios` determines the project build configuration, and how to configure it manually, refer to the [`hie-bios` README](https://github.com/mpickering/hie-bios/blob/master/README.md).** - -At the moment, `haskell-language-server` has some limited support to automatically detect your project build configuration. -The plan is to improve it to handle most use cases. - -However, for now, the most reliable way is to manually configure `hie-bios` using a `hie.yaml` file in the root of the workspace. -A `hie.yaml` file **explicitly** describes how to setup the environment to compile the various parts of your project. -For that you need to know what *components* your project has, and the path associated with each one. -So you will need some knowledge about -[stack](https://docs.haskellstack.org/en/stable/build_command/#components) or [cabal](https://cabal.readthedocs.io/en/latest/cabal-commands.html?#cabal-v2-build) components. - -You also can use [this utility](https://github.com/Avi-D-coder/implicit-hie) to automatically generate `hie.yaml` files for -the most common stack and cabal configurations - -For example, to state that you want to use `stack` then the configuration file -would look like: - -```yaml -cradle: - stack: - component: "haskell-language-server:lib" -``` - -If you use `cabal` then you probably need to specify which component you want -to use. - -```yaml -cradle: - cabal: - component: "lib:haskell-language-server" -``` - -If you have a project with multiple components, you can use a cabal-multi -cradle: - -```yaml -cradle: - cabal: - - path: "./test/functional/" - component: "haskell-language-server:func-test" - - path: "./test/utils/" - component: "haskell-language-server:hls-test-utils" - - path: "./exe/Main.hs" - component: "haskell-language-server:exe:haskell-language-server" - - path: "./exe/Wrapper.hs" - component: "haskell-language-server:exe:haskell-language-server-wrapper" - - path: "./src" - component: "lib:haskell-language-server" - - path: "./ghcide/src" - component: "ghcide:lib:ghcide" - - path: "./ghcide/exe" - component: "ghcide:exe:ghcide" -``` - -Equivalently, you can use stack: - -```yaml -cradle: - stack: - - path: "./test/functional/" - component: "haskell-language-server:func-test" - - path: "./exe/Main.hs" - component: "haskell-language-server:exe:haskell-language-server" - - path: "./exe/Wrapper.hs" - component: "haskell-language-server:exe:haskell-language-server-wrapper" - - path: "./src" - component: "haskell-language-server:lib" - - path: "./ghcide/src" - component: "ghcide:lib:ghcide" - - path: "./ghcide/exe" - component: "ghcide:exe:ghcide" -``` - -Or you can explicitly state the program which should be used to collect -the options by supplying the path to the program. It is interpreted -relative to the current working directory if it is not an absolute path. - -```yaml -cradle: - bios: - program: ".hie-bios" -``` - -The complete configuration is a subset of - -```yaml -cradle: - cabal: - component: "optional component name" - stack: - component: "optional component name" - bios: - program: "program to run" - dependency-program: "optional program to run" - direct: - arguments: ["list","of","ghc","arguments"] - default: - none: - -dependencies: - - someDep -``` - -## Configuring your editor - -Most editors provide a Haskell-specific extension that provides support for launching `haskell-language-server` and talking to it, as well as [exposing configuration options](#configuring-haskell-language-server). - -Editors typically assume that you have already installed `haskell-language-server` (see above) and that the installation script put the `haskell-language-server` and `haskell-language-server-wrapper` binaries in your `PATH` (usually `~/.local/bin` or `~/.cabal/bin` on Linux and macOS, `%APPDATA%\local\bin` or `%APPDATA%\cabal\bin` on Windows). -The exception is VS Code, which can automatically install the binaries if they are not installed already. - -### Using Haskell Language Server with VS Code - -Install from -[the VSCode marketplace](https://marketplace.visualstudio.com/items?itemName=haskell.haskell), or manually from the repository [vscode-haskell](https://github.com/haskell/vscode-haskell). -The `haskell-language-server` and `haskell-language-server-wrapper` binaries will be automatically downloaded on an ad-hoc basis, but if you have them already installed on your PATH then it will just use them instead. - -Configuration is done via the "Haskell" section of "Settings". - -### Using Haskell Language Server with Sublime Text - -- Install [LSP](https://packagecontrol.io/packages/LSP) using [Package Control](https://packagecontrol.io/) -- From Sublime Text, go to Preferences and search for LSP Settings -- Paste in these settings. Make sure to change the command path to your `haskell-language-server-wrapper` - -```json -{ - "clients": { - "haskell-language-server": { - "command": ["haskell-language-server-wrapper", "--lsp"], - "scopes": ["source.haskell"], - "syntaxes": ["Packages/Haskell/Haskell.sublime-syntax"], - "languageId": "haskell" - } - } -} -``` - -Now open a Haskell project with Sublime Text and enable Language Server in the project. -You should have these features available: - -1. Errors are underlined in red -2. LSP: Show Diagnostics will show a list of hints and errors -3. LSP: Format Document will prettify the file - -### Using Haskell Language Server with Vim or Neovim - -You can use [Coc](https://github.com/neoclide/coc.nvim), [LanguageClient-neovim](https://github.com/autozimu/LanguageClient-neovim) -or any other Vim Language server protocol client. -Coc is recommend since it is the only complete LSP implementation for Vim and Neovim and offers snippets and floating documentation out of the box. - -#### Coc - -Follow Coc's [installation instructions](https://github.com/neoclide/coc.nvim). -Then issue `:CocConfig` and add the following to your Coc config file. - -```json -{ - "languageserver": { - "haskell": { - "command": "haskell-language-server-wrapper", - "args": ["--lsp"], - "rootPatterns": ["*.cabal", "stack.yaml", "cabal.project", "package.yaml", "hie.yaml"], - "filetypes": ["haskell", "lhaskell"] - } - } -} -``` - -#### LanguageClient-neovim - -##### vim-plug - -If you use [vim-plug](https://github.com/junegunn/vim-plug), then you can do this by e.g., -including the following line in the Plug section of your `init.vim` or `~/.vimrc`: - -```text -Plug 'autozimu/LanguageClient-neovim', { - \ 'branch': 'next', - \ 'do': 'bash install.sh' - \ } -``` - -and issuing a `:PlugInstall` command within Neovim or Vim. - -##### Clone the LanguageClient-neovim repo - -As an alternative to using [vim-plug](https://github.com/junegunn/vim-plug) shown above, clone [LanguageClient-neovim](https://github.com/autozimu/LanguageClient-neovim) -into `~/.vim/pack/XXX/start/`, where `XXX` is just a name for your "plugin suite". - -##### Configuration and sample `~/.vimrc` sections - -```vim -set rtp+=~/.vim/pack/XXX/start/LanguageClient-neovim -let g:LanguageClient_serverCommands = { 'haskell': ['haskell-language-server-wrapper', '--lsp'] } -``` - -You'll probably want to add some mappings for common commands: - -```vim -nnoremap <F5> :call LanguageClient_contextMenu()<CR> -map <Leader>lk :call LanguageClient#textDocument_hover()<CR> -map <Leader>lg :call LanguageClient#textDocument_definition()<CR> -map <Leader>lr :call LanguageClient#textDocument_rename()<CR> -map <Leader>lf :call LanguageClient#textDocument_formatting()<CR> -map <Leader>lb :call LanguageClient#textDocument_references()<CR> -map <Leader>la :call LanguageClient#textDocument_codeAction()<CR> -map <Leader>ls :call LanguageClient#textDocument_documentSymbol()<CR> -``` - -Use <kbd>Ctrl+x</kbd><kbd>Ctrl+o</kbd> (`<C-x><C-o>`) to open up the auto-complete menu, -or for asynchronous auto-completion, follow the setup instructions on -[LanguageClient](https://github.com/autozimu/LanguageClient-neovim). - -If you'd like diagnostics to be highlighted, add a highlight group for `ALEError`/`ALEWarning`/`ALEInfo`, -or customize `g:LanguageClient_diagnosticsDisplay`: - -```vim -hi link ALEError Error -hi Warning term=underline cterm=underline ctermfg=Yellow gui=undercurl guisp=Gold -hi link ALEWarning Warning -hi link ALEInfo SpellCap -``` - -If you're finding that the server isn't starting at the correct project root, -it may also be helpful to also specify root markers: - -```vim -let g:LanguageClient_rootMarkers = ['*.cabal', 'stack.yaml'] -``` - -Further configuration can be done by pointing the [`g:LanguageClient_settingsPath`](https://github.com/autozimu/LanguageClient-neovim/blob/0e5c9546bfddbaa2b01e5056389c25aefc8bf989/doc/LanguageClient.txt#L221) -variable to the file in which you want to keep your LSP settings. - -### Using Haskell Language Server with Atom - -Install the two Atom packages [atom-ide-ui](https://atom.io/packages/atom-ide-ui) and [haskell](https://atom.io/packages/haskell), - -```bash -$ apm install language-haskell atom-ide-ui haskell -``` - -### Using haskell-language-server with Emacs - -Emacs support is provided by a combination of the following packages: - -[lsp-mode](https://github.com/emacs-lsp/lsp-mode) -[lsp-ui](https://github.com/emacs-lsp/lsp-ui) -[lsp-haskell](https://github.com/emacs-lsp/lsp-haskell) - -You can install these manually if you are using plain Emacs; instructions for some specific flavours -are included below. - -Make sure to check the READMEs of each of these packages, which explain how to configure the -various parts of the Emacs integration. -In particular, `lsp-haskell` provides customization options for the `haskell-language-server`-specific parts, -such as the path to the server executable. - -#### Using haskell-language-server with [doom-emacs](https://github.com/hlissner/doom-emacs/tree/develop/modules/lang/haskell#module-flags) - -Manual installation of packages is not required. -Enable the lsp module and the haskell lang module with lsp flag in `.doom.d/init.el`: - -``` emacs-lisp -:tools -lsp -;; ... -:lang -(haskell +lsp) -``` - -then do `$HOME/.emacs.d/bin/doom sync` - -#### Using haskell-language-server with [Spacemacs](https://github.com/syl20bnr/spacemacs) - -Manual installation of packages is not required. -Enable the `haskell` layer and the `lsp` layer in your Spacemacs config file: - -```emacs-lisp -dotspacemacs-configuration-layers - '( - haskell - lsp - ;; ... - ) -``` - -### Using haskell-language-server with [Kakoune](https://github.com/mawww/kakoune) - -1. Grab a copy of [kak-lsp](https://github.com/ul/kak-lsp), and follow the setup instructions. -2. Point your `kak-lsp.toml` to `haskell-language-server-wrapper`. - -```toml -[language.haskell] -filetypes = ["haskell"] -roots = ["Setup.hs", "stack.yaml", "*.cabal"] -command = "haskell-language-server-wrapper" -args = ["--lsp"] -``` - -## Known limitations - -### Preprocessor -HLS is not yet able to find project preprocessors, which may result in `could not execute: <preprocessor>` errors. This problem is -tracked in https://github.com/haskell/haskell-language-server/issues/176 and originally comes from https://github.com/mpickering/hie-bios/issues/125 - -As a workaround, you need to ensure the preprocessor is available in the path (install globally with Stack or Cabal, provide in `shell.nix`, etc.). - -Example with `tasty-discover`: -```haskell -{-# OPTIONS_GHC -F -pgmF tasty-discover #-} -``` -This returns an error in HLS if 'tasty-discover' is not in the path: `could not execute: tasty-discover`. - -## Troubleshooting - -### Common issues - -#### Difficulties with Stack and `Paths_` modules - -These are known to be somewhat buggy at the moment: https://github.com/haskell/haskell-language-server/issues/478. -This issue should be fixed in Stack versions >= 2.5. - -#### Problems with dynamic linking - -As haskell-language-server prebuilt binaries are statically linked, they don't play well with projects using dynamic linking. -An usual symptom is the presence of errors containing `unknown symbol` and it is typical in arch linux, where a dynamically linked version of ghc is used. - -The workaround is to use a version of haskell-language-server compiled from source with `-dynamic` enabled`. See more details [here](https://github.com/haskell/haskell-language-server/issues/1160#issuecomment-756566273). - -### Troubleshooting the server - -#### Diagnostic mode - -The `haskell-language-server` executable can be run in diagnostic mode, where it will just try to load modules from your project, printing all of its output to stdout. -This makes it much easier to see what's going on and to diagnose build-related problems. - -To do this, simply run the executable directly from your shell in the project root. -You can either run it without an argument, in which case it will load random modules, or with a path, in which case it will load modules in that file or directory. - -#### Examining the log - -Most clients will launch `haskell-language-server` with `--logfile` to make it write a log file. -Please consult the documentation for your client to find out where this is (or how to set it). - -The log will contain all the messages that are sent to the server and its responses. -This is helpful for low-level debugging: if you expect a certain action to happen, you can look in the log to see if the corresponding messages are -sent, or if there are any errors. - -To get a more verbose, also pass `--debug` to the executable. - -### Troubleshooting the client - -Many clients provide diagnostic information about a LSP session. -In particular, look for a way to get the status of the server, the server stderr, or a log of the messages that the client has sent to the server. -For example, `lsp-mode` provides all of these (see its [troubleshooting page](https://emacs-lsp.github.io/lsp-mode/page/troubleshooting/) for details). - -The most common client-related problem is the client simply not finding the server executable, so make sure that you have the right `PATH` and you have configured -it to look for the right executable. - -## Contributing - -:heart: The Haskell tooling dream is near, we need your help! :heart: - -- Join [our IRC channel](https://webchat.freenode.net/?channels=haskell-language-server) at `#haskell-language-server` on `freenode`. -- Fork this repo and [ghcide](https://github.com/haskell/ghcide) and hack as much as you can. - -### Style guidelines - -The project includes a [`.editorconfig`](https://editorconfig.org) [file](https://github.com/haskell/haskell-language-server/blob/master/.editorconfig) with the editor basic settings used by the project. -However, most editors will need some action to honour those settings automatically. -For example vscode needs to have installed a specific [extension](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig). -Please, try to follow those basic settings to keep the codebase as uniform as possible. - -### Building haskell-language-server - -The project can be built with both `cabal build` and `stack build`. - -haskell-language-server can also be used with itself. We provide preset samples of `hie.yaml` for Cabal and Stack. - -Note: the `./install/` folder is not directly tied to the project so it has dedicated `./install/hie.yaml.[cbl|stack]` -templates. - -#### Using Cabal - -```shell -$ cp hie-cabal.yaml hie.yaml -$ cp install/hie-cabal.yaml install/hie.yaml -``` - -#### Using Stack - -```shell -$ cp hie-stack.yaml hie.yaml -$ cp install/hie-stack.yaml install/hie.yaml -$ cp ghcide/hie-stack.yaml ghcide/hie.yaml -$ stack build --test --no-run-tests -$ cd install -$ stack build -``` - -#### Using Nix - -The instructions below show how to set up a Cachix binary cache and open a nix shell for local development. - -```shell -$ cachix use haskell-language-server -$ nix-shell -$ cabal update -$ cabal build -``` - -If you are looking for a Nix expression to create haskell-language-server binaries, see https://github.com/haskell/haskell-language-server/issues/122 - -#### Introduction tutorial -Pepeiborra [wrote an tutorial](https://github.com/pepeiborra/hls-tutorial) on writing a plugin in HLS. - -#### Test your hacked HLS in your editor -If you want to test HLS while hacking on it, follow the steps below. - -To do once: -- Open some codebase on which you want to test your hacked HLS in your favorite editor -- Configure this editor to use your custom HLS executable - - With Cabal: - - On Unix systems: `cabal exec which haskell-language-server` - - On Windows: `cabal exec where haskell-language-server` - - With Stack: `$(stack path --dist-dir)/build/haskell-language-server/haskell-language-server` - -To do every time you changed code and want to test it: -- Build HLS - - With Cabal: `cabal build exe:haskell-language-server` - - With Stack: `stack build haskell-language-server:exe:haskell-language-server` -- Restart HLS - - With VS Code: `Haskell: Restart Haskell LSP Server` - -### Adding support for a new editor - -Adding support for new editors is fairly easy if the editor already has good support for generic LSP-based extensions. -In that case, there will likely be an editor-specific support system for this (like `lsp-mode` for Emacs). -This will typically provide instructions for how to support new languages. - -In some cases you may need to write a small bit of additional client support, or expose a way for the user to set the server's [configuration options](#configuring-haskell-language-server) and -for them to configure how the server is started. +# haskell-language-server++![haskell-language-server][logo]++[![Hackage][badge-hackage]][hackage]+[![License Apache 2.0][badge-license]][license]+[![CircleCI][badge-circleci]][circleci]++++[logo]: ./docs/logos/logo-256.png+[badge-license]: https://img.shields.io/badge/license-Apache2-green.svg?dummy+[license]: https://github.com/haskell/haskell-language-server/blob/master/LICENSE+[badge-circleci]: https://img.shields.io/circleci/project/github/haskell/haskell-language-server/master.svg+[circleci]: https://circleci.com/gh/haskell/haskell-language-server/+[badge-hackage]: https://img.shields.io/hackage/v/haskell-language-server.svg?logo=haskell+[hackage]: https://hackage.haskell.org/package/haskell-language-server++Integration point for [ghcide](https://github.com/haskell/ghcide) and [haskell-ide-engine](https://github.com/haskell/haskell-ide-engine). One IDE to rule+them all. Read the [project's+background](https://neilmitchell.blogspot.com/2020/01/one-haskell-ide-to-rule-them-all.html).++- [haskell-language-server](#haskell-language-server)+ - [Features](#features)+ - [Installation](#installation)+ - [Prerequisites](#prerequisites)+ - [ghcup](#ghcup)+ - [Visual Studio Code](#visual-studio-code)+ - [Pre-built binaries](#pre-built-binaries)+ - [Arch Linux](#arch-linux)+ - [Installation from source](#installation-from-source)+ - [Common pre-requirements](#common-pre-requirements)+ - [Linux-specific pre-requirements](#linux-specific-pre-requirements)+ - [Windows-specific pre-requirements](#windows-specific-pre-requirements)+ - [Download the source code](#download-the-source-code)+ - [Building](#building)+ - [Install via cabal](#install-via-cabal)+ - [Install specific GHC Version](#install-specific-ghc-version)+ - [Installation from Hackage](#installation-from-hackage)+ - [Configuring `haskell-language-server`](#configuring-haskell-language-server)+ - [Generic server options](#generic-server-options)+ - [Generic editor options](#generic-editor-options)+ - [Language-specific server options](#language-specific-server-options)+ - [Client options](#client-options)+ - [Configuring your project build](#configuring-your-project-build)+ - [Configuring your editor](#configuring-your-editor)+ - [VS Code](#vs-code)+ - [Sublime Text](#sublime-text)+ - [Vim or Neovim](#vim-or-neovim)+ - [Coc](#coc)+ - [LanguageClient-neovim](#languageclient-neovim)+ - [vim-plug](#vim-plug)+ - [Clone the LanguageClient-neovim repo](#clone-the-languageclient-neovim-repo)+ - [Configuration and sample `~/.vimrc` sections](#configuration-and-sample-vimrc-sections)+ - [Atom](#atom)+ - [Emacs](#emacs)+ - [doom-emacs](#doom-emacs)+ - [Spacemacs](#spacemacs)+ - [Kakoune](#kakoune)+ - [Known limitations](#known-limitations)+ - [Preprocessor](#preprocessor)+ - [Troubleshooting](#troubleshooting)+ - [Common issues](#common-issues)+ - [Difficulties with Stack and `Paths_` modules](#difficulties-with-stack-and-paths_-modules)+ - [Problems with dynamic linking](#problems-with-dynamic-linking)+ - [Troubleshooting the server](#troubleshooting-the-server)+ - [Diagnostic mode](#diagnostic-mode)+ - [Examining the log](#examining-the-log)+ - [Troubleshooting the client](#troubleshooting-the-client)+ - [Contributing](#contributing)+ - [Style guidelines](#style-guidelines)+ - [Building haskell-language-server](#building-haskell-language-server)+ - [Using Cabal](#using-cabal)+ - [Using Stack](#using-stack)+ - [Using Nix](#using-nix)+ - [Introduction tutorial](#introduction-tutorial)+ - [Test your hacked HLS in your editor](#test-your-hacked-hls-in-your-editor)+ - [Adding support for a new editor](#adding-support-for-a-new-editor)++## Features++- Code evaluation codelens ([Tutorial](plugins/hls-eval-plugin/README.md)):++ ++- Type information and documentation on hover. Note that currently, in order for docs to be displayed for dependencies, they must have been built with GHC's `-haddock` flag:++ - For cabal:+ - Add to your global config file (e.g. `~/.cabal/config`):++ ```cabal+ program-default-options+ ghc-options: -haddock+ ```++ - Or, for a single project, run `cabal configure --ghc-options=-haddock`++ - For stack, add to global `$STACK_ROOT\config.yaml`, or project's `stack.yaml`:++ ```cabal+ ghc-options:+ "$everything": -haddock+ ```++ This will cause compilation errors if a dependency contains invalid Haddock markup, though from GHC version 9.0, [these will be demoted to warnings](https://gitlab.haskell.org/ghc/ghc/-/merge_requests/2377).++ - Integration with [retrie](https://hackage.haskell.org/package/retrie)++ ++ - Code lenses for explicit import lists++ ++ - Many more (TBD)++## Installation++### Prerequisites++- For standalone `.hs`/`.lhs` files, [ghc](https://www.haskell.org/ghc/) must be installed and on the PATH. The easiest way to install it is with [ghcup](https://www.haskell.org/ghcup/) or [Chocolatey](https://www.haskell.org/platform/windows.html) on Windows.+- For Cabal based projects, both ghc and [cabal-install](https://www.haskell.org/cabal/) must be installed and on the PATH. It can also be installed with [ghcup](https://www.haskell.org/ghcup/) or [Chocolatey](https://www.haskell.org/platform/windows.html) on Windows.+- For Stack based projects, [stack](http://haskellstack.org) must be installed and on the PATH.++### ghcup++If you are using [`ghcup`](https://www.haskell.org/ghcup/) to manage your installations, you can install the latest version of `haskell-language-server` with+```+ghcup install hls+```++### Visual Studio Code++If you are using Visual Studio Code, the [Haskell extension](https://marketplace.visualstudio.com/items?itemName=haskell.haskell) will automatically download and install `haskell-language-server` for you.++### Pre-built binaries++There are pre-built binaries available from the [releases page](https://github.com/haskell/haskell-language-server/releases) for Linux, Windows and macOS.+To install, download the `haskell-language-server-wrapper` executable for your platform as well as any `haskell-language-server` executables for the GHC versions you plan on working with, and either put them on your PATH or point your client to them.++### Arch Linux++The preferred method of installation for development purposes is to use the [haskell-language-server-bin](https://aur.archlinux.org/packages/haskell-language-server-bin) package from AUR.+This package contains statically linked binaries for each supported GHC version and `haskell-language-server-wrapper` for automatic GHC version selection.+It is updated regularly, requires no additional dependencies, and is independent of other haskell packages you may have on your system, including GHC.+Its size is relatively large (approx. 900 MB), but if this is a problem for you, during installation you can disable the GHC versions you will not be using by editing the PKGBUILD file.++Alternatively, if you want to use **dynamically linked** Haskell packages from `pacman`,+you can install the latest pre-compiled version of `haskell-language-server` from [[community]](https://archlinux.org/packages/community/x86_64/haskell-language-server/):++```+sudo pacman -S haskell-language-server+```++In this case, `haskell-language-server` is compiled against the GHC distributed to Arch Linux, so you will need maintain a system wide Haskell development environment, and install GHC from `pacman` as well.+See [ArchWiki](https://wiki.archlinux.org/index.php/Haskell) for the details of Haskell infrastructure on Arch Linux.++### Installation from source++#### Common pre-requirements++- `stack` or `cabal` must be in your PATH+ - You need stack version >= 2.1.1 or cabal >= 2.4.0.0+- `git` must be in your PATH+- The directory where `stack`or `cabal` put the binaries must be in you PATH:+ - For stack you can get it with `stack path --local-bin`+ - For cabal it is by default `$HOME/.cabal/bin` in linux and `%APPDATA%\cabal\bin` in windows.++Tip: you can quickly check if some command is in your path by running the command.+If you receive some meaningful output instead of "command not found"-like message+then it means you have the command in PATH.++#### Linux-specific pre-requirements++On Linux you will need install a couple of extra libraries:++- [Unicode (ICU)](http://site.icu-project.org/)+- [NCURSES](https://www.gnu.org/software/ncurses/)+- [Zlib](https://zlib.net/)++**Debian 9/Ubuntu 18.04 or earlier**:++```bash+sudo apt install libicu-dev libtinfo-dev libgmp-dev zlib1g-dev+```++**Debian 10/Ubuntu 18.10 or later**:++```bash+sudo apt install libicu-dev libncurses-dev libgmp-dev zlib1g-dev+```++**Fedora**:++```bash+sudo dnf install libicu-devel ncurses-devel zlib-devel+```++#### Windows-specific pre-requirements++In order to avoid problems with long paths on Windows you can do either one of the following:++1. Clone the `haskell-language-server` to a short path, for example the root of your logical drive (e.g. to+ `C:\hls`). Even if you choose `C:\haskell-language-server` you could hit the problem. If this doesn't work or you want to use a longer path, try the second option.++2. If the `Local Group Policy Editor` is available on your system, go to: `Local Computer Policy -> Computer Configuration -> Administrative Templates -> System -> Filesystem` set `Enable Win32 long paths` to `Enabled`. If you don't have the policy editor you can use regedit by using the following instructions [here](https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#enable-long-paths-in-windows-10-version-1607-and-later). You also need to configure git to allow longer paths by using unicode paths. To set this for all your git repositories use `git config --system core.longpaths true` (you probably need an administrative shell for this) or for just this one repository use `git config core.longpaths true`.++In addition make sure `haskell-language-server.exe` is not running by closing your editor, otherwise in case of an upgrade the executable can not be installed.++#### Download the source code++```bash+git clone https://github.com/haskell/haskell-language-server --recurse-submodules+cd haskell-language-server+```++#### Building++Note, on first invocation of the build script with stack, a GHC is being installed for execution.+The GHC used for the `install.hs` can be adjusted in `./install/stack.yaml` by using a different resolver.++Available commands can be seen with:++```bash+stack ./install.hs help+```++Remember, this will take time to download a Stackage-LTS and an appropriate GHC for build+haskell-language-server the first time.++##### Install via cabal++The install-script can be invoked via `cabal` instead of `stack` with the command++```bash+cabal v2-run ./install.hs --project-file install/shake.project <target>+```++or using the existing alias script++```bash+./cabal-hls-install <target>+```++Running the script with cabal on windows requires a cabal version greater or equal to `3.0.0.0`.++For brevity, only the `stack`-based commands are presented in the following sections.++##### Install specific GHC Version++The script will install the executables `haskell-language-server-wrapper` and `haskell-language-server`.++It will copy the latter appending the used ghc version, needed by the wrapper to choose the suitable version+for the project at hand.++So installing the executables directly with `stack install` or `cabal v2-install` may not be enough+for it to work properly.++Install haskell-language-server for the latest available and supported GHC version (and hoogle docs):++```bash+stack ./install.hs hls+```++Install haskell-language-server for a specific GHC version (and hoogle docs):++```bash+stack ./install.hs hls-8.8.3+```++`hls-8.8.3` target will build the project and install `haskell-language-server-wrapper`,+`haskell-language-server`, `haskell-language-server-8.8.3` and `haskell-language-server-8.8`+executables.++The Haskell Language Server can also be built with `cabal v2-build` instead of `stack build`.+This has the advantage that you can decide how the GHC versions have been installed.+To see what GHC versions are available, the command `cabal-hls-install ghcs` can be used.+It will list all *supported* GHC versions that are on the path for build with their respective installation directory.+If you think, this list is incomplete, you can try to modify the PATH variable, such that the executables can be found.+Note, that the targets `hls` and `data` depend on the found GHC versions.++An example output is:++```bash+> ./cabal-hls-install ghcs+******************************************************************+Found the following GHC paths:+ghc-8.6.5: /opt/bin/ghc-8.6.5+ghc-8.8.3: /opt/bin/ghc-8.8.3++******************************************************************+```++If your desired ghc has been found, you use it to install haskell-language-server.++```bash+./cabal-hls-install hls-8.6.5+```++### Installation from Hackage++Direct installation from Hackage, while possible via `cabal install haskell-language-server`, is not recommended for most people.+Said command builds the `haskell-language-server` binary and installs it in the default Cabal binaries folder,+but the binary will only work with projects that use the same GHC version that built it.++The package can be found here on Hackage: <https://hackage.haskell.org/package/haskell-language-server>++## Configuring `haskell-language-server`++Language servers like `haskell-language-server` expose most of their configuration via the client (i.e. the editor).+That means that the way in which you configure the settings will depend on the client.++Most clients (editors) already have an opinion about how settings should be configured!+For example, in VS Code you use the graphical Settings tab or `settings.json`, whereas in Emacs you use customization variables.+In the [editor configuration section](#configuring-your-editor) we give some pointers for popular editors, but you should consult the documentation for your specific editor if you have trouble.++However, we can say some high-level things about the kinds of configuration `haskell-language-server` uses, and how to use them.+This can sound a bit confusing, but ultimately the client should present you with these options in a user-friendly way that makes sense for that editor.++### Generic server options++The LSP protocol is designed to support many useful server configuration options generically.+These are sent to the server by the client, and can be controlled without reference to a specific language.++For example, there are protocol methods for highlighting matching identifiers throughout a document.+This is a capability which any server can implement, so the client can decide generically whether to ask the server to do it or not.+So your editor can provide a setting to turn this on or off globally, for any language server you might use.++Settings like this are typically provided by the generic LSP client support for your editor, for example in Emacs by `lsp-mode`.++### Generic editor options++Your editor may provide some settings that affect how the information from the language server is used.+For example, whether popups are shown, or whether code lenses appear by default.++Settings like this are typically provided by the generic LSP client support for your editor, for example in Emacs by `lsp-mode`.++### Language-specific server options++A specific language server can also have its own configuration options.+These are still sent to the server by the client, but they can only be controlled by a specific client that knows about those options.++For example, `haskell-language-server` allows you to choose the formatting provider which will be used for formatting Haskell source.+This option obviously would not make sense for language servers for other languages, or even for other Haskell language servers (which need not even support formatting).++Here is a list of the additional settings currently supported by `haskell-language-server`, along with their setting key (you may not need to know this) and default:++- Formatting provider (`haskell.formattingProvider`, default `ormolu`): what formatter to use; one of `floskell`, `ormolu`, `fourmolu`, `stylish-haskell`, or `brittany` (if compiled with the brittany plugin)+- Format on imports (`haskell.formatOnImportOn`, default true): whether to format after adding an import+- Diagnostics on change (`haskell.diagnosticsOnChange`, default true): (currently unused)+- Completion snippets (`haskell.completionSnippetsOn`, default true): whether to support completion snippets+- Liquid Haskell (`haskell.liquidOn`, default false): whether to enable Liquid Haskell support (currently unused until the Liquid Haskell support is functional again)+- Hlint (`haskell.hlintOn`, default true): whether to enable Hlint support+- Max completions (`haskell.maxCompletions`, default 40): maximum number of completions sent to the LSP client.++Settings like this are typically provided by the language-specific LSP client support for your editor, for example in Emacs by `lsp-haskell`.++### Client options++A particular client might also have some options of its own, for example to control how the server executable is started.++Settings like this are typically be provided by the language-specific LSP client support for your editor, for example in Emacs by `lsp-haskell`.++## Configuring your project build++`haskell-language-server` has to compile your project in order to give you diagnostics, which means that it needs to know how to do so.+This is handled by the [`hie-bios`](https://github.com/mpickering/hie-bios) project.++**For a full explanation of how `hie-bios` determines the project build configuration, and how to configure it manually, refer to the [`hie-bios` README](https://github.com/mpickering/hie-bios/blob/master/README.md).**++At the moment, `haskell-language-server` has some limited support to automatically detect your project build configuration.+The plan is to improve it to handle most use cases.++However, for now, the most reliable way is to manually configure `hie-bios` using a `hie.yaml` file in the root of the workspace.+A `hie.yaml` file **explicitly** describes how to setup the environment to compile the various parts of your project.+For that you need to know what *components* your project has, and the path associated with each one.+So you will need some knowledge about+[stack](https://docs.haskellstack.org/en/stable/build_command/#components) or [cabal](https://cabal.readthedocs.io/en/latest/cabal-commands.html?#cabal-v2-build) components.++You also can use [this utility](https://github.com/Avi-D-coder/implicit-hie) to automatically generate `hie.yaml` files for+the most common stack and cabal configurations++For example, to state that you want to use `stack` then the configuration file+would look like:++```yaml+cradle:+ stack:+ component: "haskell-language-server:lib"+```++If you use `cabal` then you probably need to specify which component you want+to use.++```yaml+cradle:+ cabal:+ component: "lib:haskell-language-server"+```++If you have a project with multiple components, you can use a cabal-multi+cradle:++```yaml+cradle:+ cabal:+ - path: "./test/functional/"+ component: "haskell-language-server:func-test"+ - path: "./test/utils/"+ component: "haskell-language-server:hls-test-utils"+ - path: "./exe/Main.hs"+ component: "haskell-language-server:exe:haskell-language-server"+ - path: "./exe/Wrapper.hs"+ component: "haskell-language-server:exe:haskell-language-server-wrapper"+ - path: "./src"+ component: "lib:haskell-language-server"+ - path: "./ghcide/src"+ component: "ghcide:lib:ghcide"+ - path: "./ghcide/exe"+ component: "ghcide:exe:ghcide"+```++Equivalently, you can use stack:++```yaml+cradle:+ stack:+ - path: "./test/functional/"+ component: "haskell-language-server:func-test"+ - path: "./exe/Main.hs"+ component: "haskell-language-server:exe:haskell-language-server"+ - path: "./exe/Wrapper.hs"+ component: "haskell-language-server:exe:haskell-language-server-wrapper"+ - path: "./src"+ component: "haskell-language-server:lib"+ - path: "./ghcide/src"+ component: "ghcide:lib:ghcide"+ - path: "./ghcide/exe"+ component: "ghcide:exe:ghcide"+```++Or you can explicitly state the program which should be used to collect+the options by supplying the path to the program. It is interpreted+relative to the current working directory if it is not an absolute path.++```yaml+cradle:+ bios:+ program: ".hie-bios"+```++The complete configuration is a subset of++```yaml+cradle:+ cabal:+ component: "optional component name"+ stack:+ component: "optional component name"+ bios:+ program: "program to run"+ dependency-program: "optional program to run"+ direct:+ arguments: ["list","of","ghc","arguments"]+ default:+ none:++dependencies:+ - someDep+```++## Configuring your editor++Most editors provide a Haskell-specific extension that provides support for launching `haskell-language-server` and talking to it, as well as [exposing configuration options](#configuring-haskell-language-server).++Editors typically assume that you have already installed `haskell-language-server` (see above) and that the installation script put the `haskell-language-server` and `haskell-language-server-wrapper` binaries in your `PATH` (usually `~/.local/bin` or `~/.cabal/bin` on Linux and macOS, `%APPDATA%\local\bin` or `%APPDATA%\cabal\bin` on Windows).+The exception is VS Code, which can automatically install the binaries if they are not installed already.++### VS Code++Install from+[the VSCode marketplace](https://marketplace.visualstudio.com/items?itemName=haskell.haskell), or manually from the repository [vscode-haskell](https://github.com/haskell/vscode-haskell).+The `haskell-language-server` and `haskell-language-server-wrapper` binaries will be automatically downloaded on an ad-hoc basis, but if you have them already installed on your PATH then it will just use them instead.++Configuration is done via the "Haskell" section of "Settings".++### Sublime Text++- Install [LSP](https://packagecontrol.io/packages/LSP) using [Package Control](https://packagecontrol.io/)+- From Sublime Text, go to Preferences and search for LSP Settings+- Paste in these settings. Make sure to change the command path to your `haskell-language-server-wrapper`++```json+{+ "clients": {+ "haskell-language-server": {+ "command": ["haskell-language-server-wrapper", "--lsp"],+ "scopes": ["source.haskell"],+ "syntaxes": ["Packages/Haskell/Haskell.sublime-syntax"],+ "languageId": "haskell"+ }+ }+}+```++Now open a Haskell project with Sublime Text and enable Language Server in the project.+You should have these features available:++1. Errors are underlined in red+2. LSP: Show Diagnostics will show a list of hints and errors+3. LSP: Format Document will prettify the file++### Vim or Neovim++You can use [Coc](https://github.com/neoclide/coc.nvim), [LanguageClient-neovim](https://github.com/autozimu/LanguageClient-neovim)+or any other Vim Language server protocol client.+Coc is recommend since it is the only complete LSP implementation for Vim and Neovim and offers snippets and floating documentation out of the box.++#### Coc++Follow Coc's [installation instructions](https://github.com/neoclide/coc.nvim).+Then issue `:CocConfig` and add the following to your Coc config file.++```json+{+ "languageserver": {+ "haskell": {+ "command": "haskell-language-server-wrapper",+ "args": ["--lsp"],+ "rootPatterns": ["*.cabal", "stack.yaml", "cabal.project", "package.yaml", "hie.yaml"],+ "filetypes": ["haskell", "lhaskell"]+ }+ }+}+```++#### LanguageClient-neovim++##### vim-plug++If you use [vim-plug](https://github.com/junegunn/vim-plug), then you can do this by e.g.,+including the following line in the Plug section of your `init.vim` or `~/.vimrc`:++```text+Plug 'autozimu/LanguageClient-neovim', {+ \ 'branch': 'next',+ \ 'do': 'bash install.sh'+ \ }+```++and issuing a `:PlugInstall` command within Neovim or Vim.++##### Clone the LanguageClient-neovim repo++As an alternative to using [vim-plug](https://github.com/junegunn/vim-plug) shown above, clone [LanguageClient-neovim](https://github.com/autozimu/LanguageClient-neovim)+into `~/.vim/pack/XXX/start/`, where `XXX` is just a name for your "plugin suite".++##### Configuration and sample `~/.vimrc` sections++```vim+set rtp+=~/.vim/pack/XXX/start/LanguageClient-neovim+let g:LanguageClient_serverCommands = { 'haskell': ['haskell-language-server-wrapper', '--lsp'] }+```++You'll probably want to add some mappings for common commands:++```vim+nnoremap <F5> :call LanguageClient_contextMenu()<CR>+map <Leader>lk :call LanguageClient#textDocument_hover()<CR>+map <Leader>lg :call LanguageClient#textDocument_definition()<CR>+map <Leader>lr :call LanguageClient#textDocument_rename()<CR>+map <Leader>lf :call LanguageClient#textDocument_formatting()<CR>+map <Leader>lb :call LanguageClient#textDocument_references()<CR>+map <Leader>la :call LanguageClient#textDocument_codeAction()<CR>+map <Leader>ls :call LanguageClient#textDocument_documentSymbol()<CR>+```++Use <kbd>Ctrl+x</kbd><kbd>Ctrl+o</kbd> (`<C-x><C-o>`) to open up the auto-complete menu,+or for asynchronous auto-completion, follow the setup instructions on+[LanguageClient](https://github.com/autozimu/LanguageClient-neovim).++If you'd like diagnostics to be highlighted, add a highlight group for `ALEError`/`ALEWarning`/`ALEInfo`,+or customize `g:LanguageClient_diagnosticsDisplay`:++```vim+hi link ALEError Error+hi Warning term=underline cterm=underline ctermfg=Yellow gui=undercurl guisp=Gold+hi link ALEWarning Warning+hi link ALEInfo SpellCap+```++If you're finding that the server isn't starting at the correct project root,+it may also be helpful to also specify root markers:++```vim+let g:LanguageClient_rootMarkers = ['*.cabal', 'stack.yaml']+```++Further configuration can be done by pointing the [`g:LanguageClient_settingsPath`](https://github.com/autozimu/LanguageClient-neovim/blob/0e5c9546bfddbaa2b01e5056389c25aefc8bf989/doc/LanguageClient.txt#L221)+variable to the file in which you want to keep your LSP settings.++### Atom++Install the two Atom packages [atom-ide-ui](https://atom.io/packages/atom-ide-ui) and [haskell](https://atom.io/packages/haskell),++```bash+$ apm install language-haskell atom-ide-ui haskell+```++### Emacs++Emacs support is provided by a combination of the following packages:++[lsp-mode](https://github.com/emacs-lsp/lsp-mode)+[lsp-ui](https://github.com/emacs-lsp/lsp-ui)+[lsp-haskell](https://github.com/emacs-lsp/lsp-haskell)++You can install these manually if you are using plain Emacs; instructions for some specific flavours+are included below.++Make sure to check the READMEs of each of these packages, which explain how to configure the+various parts of the Emacs integration.+In particular, `lsp-haskell` provides customization options for the `haskell-language-server`-specific parts,+such as the path to the server executable.++#### [doom-emacs](https://github.com/hlissner/doom-emacs/tree/develop/modules/lang/haskell#module-flags)++Manual installation of packages is not required.+Enable the lsp module and the haskell lang module with lsp flag in `.doom.d/init.el`:++``` emacs-lisp+:tools+lsp+;; ...+:lang+(haskell +lsp)+```++then do `$HOME/.emacs.d/bin/doom sync`++#### [Spacemacs](https://github.com/syl20bnr/spacemacs)++Manual installation of packages is not required.+Enable the `haskell` layer and the `lsp` layer in your Spacemacs config file:++```emacs-lisp+dotspacemacs-configuration-layers+ '(+ haskell+ lsp+ ;; ...+ )+```++### [Kakoune](https://github.com/mawww/kakoune)++1. Grab a copy of [kak-lsp](https://github.com/ul/kak-lsp), and follow the setup instructions.+2. Point your `kak-lsp.toml` to `haskell-language-server-wrapper`.++```toml+[language.haskell]+filetypes = ["haskell"]+roots = ["Setup.hs", "stack.yaml", "*.cabal"]+command = "haskell-language-server-wrapper"+args = ["--lsp"]+```++## Known limitations++### Preprocessor+HLS is not yet able to find project preprocessors, which may result in `could not execute: <preprocessor>` errors. This problem is+tracked in https://github.com/haskell/haskell-language-server/issues/176 and originally comes from https://github.com/mpickering/hie-bios/issues/125++As a workaround, you need to ensure the preprocessor is available in the path (install globally with Stack or Cabal, provide in `shell.nix`, etc.).++Example with `tasty-discover`:++```haskell+{-# OPTIONS_GHC -F -pgmF tasty-discover #-}+```++This returns an error in HLS if 'tasty-discover' is not in the path: `could not execute: tasty-discover`.++## Troubleshooting++### Common issues++#### Difficulties with Stack and `Paths_` modules++These are known to be somewhat buggy at the moment: <https://github.com/haskell/haskell-language-server/issues/478>.+This issue should be fixed in Stack versions >= 2.5.++#### Problems with dynamic linking++As haskell-language-server prebuilt binaries are statically linked, they don't play well with projects using dynamic linking.+An usual symptom is the presence of errors containing `unknown symbol` and it is typical in arch linux, where a dynamically linked version of ghc is used.++The workaround is to use a version of haskell-language-server compiled from source with `-dynamic` enabled`. See more details [here](https://github.com/haskell/haskell-language-server/issues/1160#issuecomment-756566273).++### Troubleshooting the server++#### Diagnostic mode++The `haskell-language-server` executable can be run in diagnostic mode, where it will just try to load modules from your project, printing all of its output to stdout.+This makes it much easier to see what's going on and to diagnose build-related problems.++To do this, simply run the executable directly from your shell in the project root.+You can either run it without an argument, in which case it will load random modules, or with a path, in which case it will load modules in that file or directory.++#### Examining the log++Most clients will launch `haskell-language-server` with `--logfile` to make it write a log file.+Please consult the documentation for your client to find out where this is (or how to set it).++The log will contain all the messages that are sent to the server and its responses.+This is helpful for low-level debugging: if you expect a certain action to happen, you can look in the log to see if the corresponding messages are+sent, or if there are any errors.++To get a more verbose, also pass `--debug` to the executable.++### Troubleshooting the client++Many clients provide diagnostic information about a LSP session.+In particular, look for a way to get the status of the server, the server stderr, or a log of the messages that the client has sent to the server.+For example, `lsp-mode` provides all of these (see its [troubleshooting page](https://emacs-lsp.github.io/lsp-mode/page/troubleshooting/) for details).++The most common client-related problem is the client simply not finding the server executable, so make sure that you have the right `PATH` and you have configured+it to look for the right executable.++## Contributing++:heart: The Haskell tooling dream is near, we need your help! :heart:++- Join [our IRC channel](https://webchat.freenode.net/?channels=haskell-language-server) at `#haskell-language-server` on `freenode`.+- Fork this repo and [ghcide](https://github.com/haskell/ghcide) and hack as much as you can.++### Style guidelines++The project includes a [`.editorconfig`](https://editorconfig.org) [file](https://github.com/haskell/haskell-language-server/blob/master/.editorconfig) with the editor basic settings used by the project.+However, most editors will need some action to honour those settings automatically.+For example vscode needs to have installed a specific [extension](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig).+Please, try to follow those basic settings to keep the codebase as uniform as possible.++### Building haskell-language-server++The project can be built with both `cabal build` and `stack build`.++haskell-language-server can also be used with itself. We provide preset samples of `hie.yaml` for Cabal and Stack.++Note: the `./install/` folder is not directly tied to the project so it has dedicated `./install/hie.yaml.[cbl|stack]`+templates.++#### Using Cabal++```shell+$ cp hie-cabal.yaml hie.yaml+$ cp install/hie-cabal.yaml install/hie.yaml+```++#### Using Stack++```shell+$ cp hie-stack.yaml hie.yaml+$ cp install/hie-stack.yaml install/hie.yaml+$ cp ghcide/hie-stack.yaml ghcide/hie.yaml+$ stack build --test --no-run-tests+$ cd install+$ stack build+```++#### Using Nix++The instructions below show how to set up a Cachix binary cache and open a nix shell for local development.++```shell+$ cachix use haskell-language-server+$ nix-shell+$ cabal update+$ cabal build+```++If you are looking for a Nix expression to create haskell-language-server binaries, see https://github.com/haskell/haskell-language-server/issues/122++#### Introduction tutorial++Pepeiborra [wrote an tutorial](https://github.com/pepeiborra/hls-tutorial) on writing a plugin in HLS.++#### Test your hacked HLS in your editor++If you want to test HLS while hacking on it, follow the steps below.++To do once:++- Open some codebase on which you want to test your hacked HLS in your favorite editor+- Configure this editor to use your custom HLS executable+ - With Cabal:+ - On Unix systems: `cabal exec which haskell-language-server`+ - On Windows: `cabal exec where haskell-language-server`+ - With Stack: `$(stack path --dist-dir)/build/haskell-language-server/haskell-language-server`++To do every time you changed code and want to test it:++- Build HLS+ - With Cabal: `cabal build exe:haskell-language-server`+ - With Stack: `stack build haskell-language-server:exe:haskell-language-server`+- Restart HLS+ - With VS Code: `Haskell: Restart Haskell LSP Server`++### Adding support for a new editor++Adding support for new editors is fairly easy if the editor already has good support for generic LSP-based extensions.+In that case, there will likely be an editor-specific support system for this (like `lsp-mode` for Emacs).+This will typically provide instructions for how to support new languages.++In some cases you may need to write a small bit of additional client support, or expose a way for the user to set the server's [configuration options](#configuring-haskell-language-server) and+for them to configure how the server is started.
@@ -1,2 +1,2 @@-import Distribution.Simple -main = defaultMain +import Distribution.Simple+main = defaultMain
@@ -1,22 +1,21 @@--- Copyright (c) 2019 The DAML Authors. All rights reserved. --- SPDX-License-Identifier: Apache-2.0 -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} -module Main(main) where - -import Ide.Arguments (Arguments (..), LspArguments (..), - getArguments) -import Ide.Main (defaultMain) -import Plugins -import Main.Utf8 (withUtf8) - -main :: IO () -main = withUtf8 $ do - args <- getArguments "haskell-language-server" - - let withExamples = - case args of - LspMode LspArguments{..} -> argsExamplePlugin - _ -> False - - defaultMain args (idePlugins withExamples) +-- Copyright (c) 2019 The DAML Authors. All rights reserved.+-- SPDX-License-Identifier: Apache-2.0+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+module Main(main) where++import Ide.Arguments (Arguments (..), GhcideArguments (..),+ getArguments)+import Ide.Main (defaultMain)+import Plugins++main :: IO ()+main = do+ args <- getArguments "haskell-language-server"++ let withExamples =+ case args of+ Ghcide GhcideArguments{..} -> argsExamplePlugin+ _ -> False++ defaultMain args (idePlugins withExamples)
@@ -1,142 +1,143 @@-{-# LANGUAGE CPP #-} -{-# LANGUAGE OverloadedStrings #-} -module Plugins where - -import Ide.Types (IdePlugins) -import Ide.PluginUtils (pluginDescToIdePlugins) - --- fixed plugins -import Ide.Plugin.Example as Example -import Ide.Plugin.Example2 as Example2 -import Development.IDE (IdeState) -import Development.IDE.Plugin.HLS.GhcIde as GhcIde - --- haskell-language-server optional plugins - -#if class -import Ide.Plugin.Class as Class -#endif - -#if haddockComments -import Ide.Plugin.HaddockComments as HaddockComments -#endif - -#if eval -import Ide.Plugin.Eval as Eval -#endif - -#if importLens -import Ide.Plugin.ExplicitImports as ExplicitImports -#endif - -#if retrie -import Ide.Plugin.Retrie as Retrie -#endif - -#if tactic -import Ide.Plugin.Tactic as Tactic -#endif - -#if hlint -import Ide.Plugin.Hlint as Hlint -#endif - -#if moduleName -import Ide.Plugin.ModuleName as ModuleName -#endif - -#if pragmas -import Ide.Plugin.Pragmas as Pragmas -#endif - -#if splice -import Ide.Plugin.Splice as Splice -#endif - --- formatters - -#if floskell -import Ide.Plugin.Floskell as Floskell -#endif - -#if fourmolu -import Ide.Plugin.Fourmolu as Fourmolu -#endif - -#if ormolu -import Ide.Plugin.Ormolu as Ormolu -#endif - -#if stylishHaskell -import Ide.Plugin.StylishHaskell as StylishHaskell -#endif - -#if AGPL && brittany -import Ide.Plugin.Brittany as Brittany -#endif - --- --------------------------------------------------------------------- - --- | The plugins configured for use in this instance of the language --- server. --- These can be freely added or removed to tailor the available --- features of the server. - -idePlugins :: Bool -> IdePlugins IdeState -idePlugins includeExamples = pluginDescToIdePlugins allPlugins - where - allPlugins = if includeExamples - then basePlugins ++ examplePlugins - else basePlugins - basePlugins = - GhcIde.descriptors ++ -#if pragmas - Pragmas.descriptor "pragmas" : -#endif -#if floskell - Floskell.descriptor "floskell" : -#endif -#if fourmolu - Fourmolu.descriptor "fourmolu" : -#endif -#if tactic - Tactic.descriptor "tactic" : -#endif -#if ormolu - Ormolu.descriptor "ormolu" : -#endif -#if stylishHaskell - StylishHaskell.descriptor "stylish-haskell" : -#endif -#if retrie - Retrie.descriptor "retrie" : -#endif -#if AGPL && brittany - Brittany.descriptor "brittany" : -#endif -#if class - Class.descriptor "class" : -#endif -#if haddockComments - HaddockComments.descriptor "haddockComments" : -#endif -#if eval - Eval.descriptor "eval" : -#endif -#if importLens - ExplicitImports.descriptor "importLens" : -#endif -#if moduleName - ModuleName.descriptor "moduleName" : -#endif -#if hlint - Hlint.descriptor "hlint" : -#endif -#if splice - Splice.descriptor "splice" : -#endif - [] - examplePlugins = - [Example.descriptor "eg" - ,Example2.descriptor "eg2" - ] +{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+module Plugins where++import Ide.PluginUtils (pluginDescToIdePlugins)+import Ide.Types (IdePlugins)++-- fixed plugins+import Development.IDE (IdeState)+import Development.IDE.Plugin.HLS.GhcIde as GhcIde+import Ide.Plugin.Example as Example+import Ide.Plugin.Example2 as Example2++-- haskell-language-server optional plugins++#if class+import Ide.Plugin.Class as Class+#endif++#if haddockComments+import Ide.Plugin.HaddockComments as HaddockComments+#endif++#if eval+import Ide.Plugin.Eval as Eval+#endif++#if importLens+import Ide.Plugin.ExplicitImports as ExplicitImports+#endif++#if retrie+import Ide.Plugin.Retrie as Retrie+#endif++#if tactic+import Ide.Plugin.Tactic as Tactic+#endif++#if hlint+import Ide.Plugin.Hlint as Hlint+#endif++#if moduleName+import Ide.Plugin.ModuleName as ModuleName+#endif++#if pragmas+import Ide.Plugin.Pragmas as Pragmas+#endif++#if splice+import Ide.Plugin.Splice as Splice+#endif++-- formatters++#if floskell+import Ide.Plugin.Floskell as Floskell+#endif++#if fourmolu+import Ide.Plugin.Fourmolu as Fourmolu+#endif++#if ormolu+import Ide.Plugin.Ormolu as Ormolu+#endif++#if stylishHaskell+import Ide.Plugin.StylishHaskell as StylishHaskell+#endif++#if brittany+import Ide.Plugin.Brittany as Brittany+#endif++-- ---------------------------------------------------------------------++-- | The plugins configured for use in this instance of the language+-- server.+-- These can be freely added or removed to tailor the available+-- features of the server.++idePlugins :: Bool -> IdePlugins IdeState+idePlugins includeExamples = pluginDescToIdePlugins allPlugins+ where+ allPlugins = if includeExamples+ then basePlugins ++ examplePlugins+ else basePlugins+ basePlugins =+#if pragmas+ Pragmas.descriptor "pragmas" :+#endif+#if floskell+ Floskell.descriptor "floskell" :+#endif+#if fourmolu+ Fourmolu.descriptor "fourmolu" :+#endif+#if tactic+ Tactic.descriptor "tactics" :+#endif+#if ormolu+ Ormolu.descriptor "ormolu" :+#endif+#if stylishHaskell+ StylishHaskell.descriptor "stylish-haskell" :+#endif+#if retrie+ Retrie.descriptor "retrie" :+#endif+#if brittany+ Brittany.descriptor "brittany" :+#endif+#if class+ Class.descriptor "class" :+#endif+#if haddockComments+ HaddockComments.descriptor "haddockComments" :+#endif+#if eval+ Eval.descriptor "eval" :+#endif+#if importLens+ ExplicitImports.descriptor "importLens" :+#endif+#if moduleName+ ModuleName.descriptor "moduleName" :+#endif+#if hlint+ Hlint.descriptor "hlint" :+#endif+#if splice+ Splice.descriptor "splice" :+#endif+ -- The ghcide descriptors should come last so that the notification handlers+ -- (which restart the Shake build) run after everything else+ GhcIde.descriptors+ examplePlugins =+ [Example.descriptor "eg"+ ,Example2.descriptor "eg2"+ ]
@@ -1,151 +1,151 @@-{-# LANGUAGE RecordWildCards #-} --- | This module is based on the hie-wrapper.sh script in --- https://github.com/alanz/vscode-hie-server -module Main where - -import Control.Monad.Extra -import Data.Default -import Data.Foldable -import Data.List -import Data.Void -import Development.IDE.Session (findCradle) -import HIE.Bios hiding (findCradle) -import HIE.Bios.Environment -import HIE.Bios.Types -import Ide.Arguments -import Ide.Version -import System.Directory -import System.Environment -import System.Exit -import System.FilePath -import System.IO -import System.Info -import System.Process - --- --------------------------------------------------------------------- - -main :: IO () -main = do - -- WARNING: If you write to stdout before runLanguageServer - -- then the language server will not work - args <- getArguments "haskell-language-server-wrapper" - - hlsVer <- haskellLanguageServerVersion - case args of - ProbeToolsMode -> do - programsOfInterest <- findProgramVersions - putStrLn hlsVer - putStrLn "Tool versions found on the $PATH" - putStrLn $ showProgramVersionOfInterest programsOfInterest - - VersionMode PrintVersion -> - putStrLn hlsVer - - VersionMode PrintNumericVersion -> - putStrLn haskellLanguageServerNumericVersion - - _ -> launchHaskellLanguageServer args - -launchHaskellLanguageServer :: Arguments -> IO () -launchHaskellLanguageServer parsedArgs = do - case parsedArgs of - LspMode LspArguments{..} -> whenJust argsCwd setCurrentDirectory - _ -> pure () - - d <- getCurrentDirectory - - -- Get the cabal directory from the cradle - cradle <- findLocalCradle (d </> "a") - setCurrentDirectory $ cradleRootDir cradle - - case parsedArgs of - LspMode LspArguments{..} -> - when argsProjectGhcVersion $ getRuntimeGhcVersion' cradle >>= putStrLn >> exitSuccess - _ -> pure () - - progName <- getProgName - hPutStrLn stderr $ "Run entered for haskell-language-server-wrapper(" ++ progName ++ ") " - ++ hlsVersion - hPutStrLn stderr $ "Current directory: " ++ d - hPutStrLn stderr $ "Operating system: " ++ os - args <- getArgs - hPutStrLn stderr $ "Arguments: " ++ show args - hPutStrLn stderr $ "Cradle directory: " ++ cradleRootDir cradle - hPutStrLn stderr $ "Cradle type: " ++ show (actionName (cradleOptsProg cradle)) - programsOfInterest <- findProgramVersions - hPutStrLn stderr "" - hPutStrLn stderr "Tool versions found on the $PATH" - hPutStrLn stderr $ showProgramVersionOfInterest programsOfInterest - hPutStrLn stderr "" - -- Get the ghc version -- this might fail! - hPutStrLn stderr "Consulting the cradle to get project GHC version..." - ghcVersion <- getRuntimeGhcVersion' cradle - hPutStrLn stderr $ "Project GHC version: " ++ ghcVersion - - let - hlsBin = "haskell-language-server-" ++ ghcVersion - backupHlsBin = - case dropWhileEnd (/='.') ghcVersion of - [] -> "haskell-language-server" - xs -> "haskell-language-server-" ++ init xs - candidates' = [hlsBin, backupHlsBin, "haskell-language-server"] - candidates = map (++ exeExtension) candidates' - - hPutStrLn stderr $ "haskell-language-server exe candidates: " ++ show candidates - - mexes <- traverse findExecutable candidates - - case asum mexes of - Nothing -> hPutStrLn stderr $ "Cannot find any haskell-language-server exe, looked for: " ++ intercalate ", " candidates - Just e -> do - hPutStrLn stderr $ "Launching haskell-language-server exe at:" ++ e - callProcess e args - --- | Version of 'getRuntimeGhcVersion' that dies if we can't get it, and also --- checks to see if the tool is missing if it is one of -getRuntimeGhcVersion' :: Show a => Cradle a -> IO String -getRuntimeGhcVersion' cradle = do - - -- See if the tool is installed - case actionName (cradleOptsProg cradle) of - Stack -> checkToolExists "stack" - Cabal -> checkToolExists "cabal" - Default -> checkToolExists "ghc" - Direct -> checkToolExists "ghc" - _ -> pure () - - ghcVersionRes <- getRuntimeGhcVersion cradle - case ghcVersionRes of - CradleSuccess ver -> do - return ver - CradleFail error -> die $ "Failed to get project GHC version:" ++ show error - CradleNone -> die "Failed get project GHC version, since we have a none cradle" - where - checkToolExists exe = do - exists <- findExecutable exe - case exists of - Just _ -> pure () - Nothing -> - die $ "Cradle requires " ++ exe ++ " but couldn't find it" ++ "\n" - ++ show cradle - --- | Find the cradle that the given File belongs to. --- --- First looks for a "hie.yaml" file in the directory of the file --- or one of its parents. If this file is found, the cradle --- is read from the config. If this config does not comply to the "hie.yaml" --- specification, an error is raised. --- --- If no "hie.yaml" can be found, the implicit config is used. --- The implicit config uses different heuristics to determine the type --- of the project that may or may not be accurate. -findLocalCradle :: FilePath -> IO (Cradle Void) -findLocalCradle fp = do - cradleConf <- findCradle def fp - crdl <- case cradleConf of - Just yaml -> do - hPutStrLn stderr $ "Found \"" ++ yaml ++ "\" for \"" ++ fp ++ "\"" - loadCradle yaml - Nothing -> loadImplicitCradle fp - hPutStrLn stderr $ "Module \"" ++ fp ++ "\" is loaded by Cradle: " ++ show crdl - return crdl +{-# LANGUAGE RecordWildCards #-}+-- | This module is based on the hie-wrapper.sh script in+-- https://github.com/alanz/vscode-hie-server+module Main where++import Control.Monad.Extra+import Data.Default+import Data.Foldable+import Data.List+import Data.Void+import Development.IDE.Session (findCradle)+import HIE.Bios hiding (findCradle)+import HIE.Bios.Environment+import HIE.Bios.Types+import Ide.Arguments+import Ide.Version+import System.Directory+import System.Environment+import System.Exit+import System.FilePath+import System.IO+import System.Info+import System.Process++-- ---------------------------------------------------------------------++main :: IO ()+main = do+ -- WARNING: If you write to stdout before runLanguageServer+ -- then the language server will not work+ args <- getArguments "haskell-language-server-wrapper"++ hlsVer <- haskellLanguageServerVersion+ case args of+ ProbeToolsMode -> do+ programsOfInterest <- findProgramVersions+ putStrLn hlsVer+ putStrLn "Tool versions found on the $PATH"+ putStrLn $ showProgramVersionOfInterest programsOfInterest++ VersionMode PrintVersion ->+ putStrLn hlsVer++ VersionMode PrintNumericVersion ->+ putStrLn haskellLanguageServerNumericVersion++ _ -> launchHaskellLanguageServer args++launchHaskellLanguageServer :: Arguments -> IO ()+launchHaskellLanguageServer parsedArgs = do+ case parsedArgs of+ Ghcide GhcideArguments{..} -> whenJust argsCwd setCurrentDirectory+ _ -> pure ()++ d <- getCurrentDirectory++ -- Get the cabal directory from the cradle+ cradle <- findLocalCradle (d </> "a")+ setCurrentDirectory $ cradleRootDir cradle++ case parsedArgs of+ Ghcide GhcideArguments{..} ->+ when argsProjectGhcVersion $ getRuntimeGhcVersion' cradle >>= putStrLn >> exitSuccess+ _ -> pure ()++ progName <- getProgName+ hPutStrLn stderr $ "Run entered for haskell-language-server-wrapper(" ++ progName ++ ") "+ ++ hlsVersion+ hPutStrLn stderr $ "Current directory: " ++ d+ hPutStrLn stderr $ "Operating system: " ++ os+ args <- getArgs+ hPutStrLn stderr $ "Arguments: " ++ show args+ hPutStrLn stderr $ "Cradle directory: " ++ cradleRootDir cradle+ hPutStrLn stderr $ "Cradle type: " ++ show (actionName (cradleOptsProg cradle))+ programsOfInterest <- findProgramVersions+ hPutStrLn stderr ""+ hPutStrLn stderr "Tool versions found on the $PATH"+ hPutStrLn stderr $ showProgramVersionOfInterest programsOfInterest+ hPutStrLn stderr ""+ -- Get the ghc version -- this might fail!+ hPutStrLn stderr "Consulting the cradle to get project GHC version..."+ ghcVersion <- getRuntimeGhcVersion' cradle+ hPutStrLn stderr $ "Project GHC version: " ++ ghcVersion++ let+ hlsBin = "haskell-language-server-" ++ ghcVersion+ backupHlsBin =+ case dropWhileEnd (/='.') ghcVersion of+ [] -> "haskell-language-server"+ xs -> "haskell-language-server-" ++ init xs+ candidates' = [hlsBin, backupHlsBin, "haskell-language-server"]+ candidates = map (++ exeExtension) candidates'++ hPutStrLn stderr $ "haskell-language-server exe candidates: " ++ show candidates++ mexes <- traverse findExecutable candidates++ case asum mexes of+ Nothing -> hPutStrLn stderr $ "Cannot find any haskell-language-server exe, looked for: " ++ intercalate ", " candidates+ Just e -> do+ hPutStrLn stderr $ "Launching haskell-language-server exe at:" ++ e+ callProcess e args++-- | Version of 'getRuntimeGhcVersion' that dies if we can't get it, and also+-- checks to see if the tool is missing if it is one of+getRuntimeGhcVersion' :: Show a => Cradle a -> IO String+getRuntimeGhcVersion' cradle = do++ -- See if the tool is installed+ case actionName (cradleOptsProg cradle) of+ Stack -> checkToolExists "stack"+ Cabal -> checkToolExists "cabal"+ Default -> checkToolExists "ghc"+ Direct -> checkToolExists "ghc"+ _ -> pure ()++ ghcVersionRes <- getRuntimeGhcVersion cradle+ case ghcVersionRes of+ CradleSuccess ver -> do+ return ver+ CradleFail error -> die $ "Failed to get project GHC version:" ++ show error+ CradleNone -> die "Failed get project GHC version, since we have a none cradle"+ where+ checkToolExists exe = do+ exists <- findExecutable exe+ case exists of+ Just _ -> pure ()+ Nothing ->+ die $ "Cradle requires " ++ exe ++ " but couldn't find it" ++ "\n"+ ++ show cradle++-- | Find the cradle that the given File belongs to.+--+-- First looks for a "hie.yaml" file in the directory of the file+-- or one of its parents. If this file is found, the cradle+-- is read from the config. If this config does not comply to the "hie.yaml"+-- specification, an error is raised.+--+-- If no "hie.yaml" can be found, the implicit config is used.+-- The implicit config uses different heuristics to determine the type+-- of the project that may or may not be accurate.+findLocalCradle :: FilePath -> IO (Cradle Void)+findLocalCradle fp = do+ cradleConf <- findCradle def fp+ crdl <- case cradleConf of+ Just yaml -> do+ hPutStrLn stderr $ "Found \"" ++ yaml ++ "\" for \"" ++ fp ++ "\""+ loadCradle yaml+ Nothing -> loadImplicitCradle fp+ hPutStrLn stderr $ "Module \"" ++ fp ++ "\" is loaded by Cradle: " ++ show crdl+ return crdl
@@ -1,7 +1,7 @@-cabal-version: 2.2+cabal-version: 2.4 category: Development name: haskell-language-server-version: 1.0.0.0+version: 1.1.0.0 synopsis: LSP server for GHC description: Please see the README on GitHub at <https://github.com/haskell/haskell-language-server#readme>@@ -19,11 +19,14 @@ README.md ChangeLog.md include/ghc-api-version.h--flag agpl- description: Enable AGPL dependencies- default: True- manual: True+ test/testdata/**/*.project+ test/testdata/**/*.cabal+ test/testdata/**/*.yaml+ -- this one is not matched by the previous glob+ test/testdata/hlint/ignore/.hlint.yaml+ test/testdata/**/*.h+ test/testdata/**/*.hs+ test/testdata/**/*.expected flag pedantic description: Enable -Werror@@ -34,10 +37,6 @@ type: git location: https://github.com/haskell/haskell-language-server -common agpl- if flag(agpl)- cpp-options: -DAGPL- common common-deps build-depends: , base >=4.12 && <5@@ -47,7 +46,7 @@ , text library- import: agpl, common-deps+ import: common-deps exposed-modules: Ide.Arguments Ide.Main@@ -64,12 +63,12 @@ , cryptohash-sha1 , data-default , ghc- , ghcide ^>= 1.0.0.0+ , ghcide ^>=1.2 , gitrev , lsp , hie-bios , hiedb- , hls-plugin-api ^>= 1.0.0.0+ , hls-plugin-api ^>= 1.1 , hslogger , optparse-applicative , optparse-simple@@ -78,6 +77,7 @@ , safe-exceptions , sqlite-simple , unordered-containers+ , aeson-pretty ghc-options: -Wall -Wredundant-constraints -Wno-name-shadowing -Wno-unticked-promoted-constructors @@ -106,37 +106,37 @@ flag class description: Enable class plugin default: True- manual: False+ manual: True flag haddockComments description: Enable haddockComments plugin default: True- manual: False+ manual: True flag eval description: Enable eval plugin default: True- manual: False+ manual: True flag importLens description: Enable importLens plugin default: True- manual: False+ manual: True flag retrie description: Enable retrie plugin default: True- manual: False+ manual: True flag tactic description: Enable tactic plugin default: True- manual: False+ manual: True flag hlint description: Enable hlint plugin default: True- manual: False+ manual: True flag moduleName description: Enable moduleName plugin@@ -151,7 +151,7 @@ flag splice description: Enable splice plugin default: True- manual: False+ manual: True -- formatters @@ -187,37 +187,37 @@ common class if flag(class) || flag(all-plugins)- build-depends: hls-class-plugin ^>= 1.0.0.0+ build-depends: hls-class-plugin ^>= 1.0.0.1 cpp-options: -Dclass common haddockComments if flag(haddockComments) || flag(all-plugins)- build-depends: hls-haddock-comments-plugin ^>= 1.0.0.0+ build-depends: hls-haddock-comments-plugin ^>= 1.0.0.1 cpp-options: -DhaddockComments common eval if flag(eval) || flag(all-plugins)- build-depends: hls-eval-plugin ^>= 1.0.0.0+ build-depends: hls-eval-plugin ^>= 1.1.0.0 cpp-options: -Deval common importLens if flag(importLens) || flag(all-plugins)- build-depends: hls-explicit-imports-plugin ^>= 1.0.0.0+ build-depends: hls-explicit-imports-plugin ^>= 1.0.0.1 cpp-options: -DimportLens common retrie if flag(retrie) || flag(all-plugins)- build-depends: hls-retrie-plugin ^>= 1.0.0.0+ build-depends: hls-retrie-plugin ^>= 1.0.0.1 cpp-options: -Dretrie common tactic if flag(tactic) || flag(all-plugins)- build-depends: hls-tactics-plugin ^>= 1.0.0.0+ build-depends: hls-tactics-plugin ^>= 1.1.0.0 cpp-options: -Dtactic common hlint if flag(hlint) || flag(all-plugins)- build-depends: hls-hlint-plugin ^>= 1.0.0.0+ build-depends: hls-hlint-plugin ^>= 1.0.0.2 cpp-options: -Dhlint common moduleName@@ -235,7 +235,7 @@ common splice if flag(splice) || flag(all-plugins)- build-depends: hls-splice-plugin ^>= 1.0.0.0+ build-depends: hls-splice-plugin ^>= 1.0.0.1 cpp-options: -Dsplice -- formatters@@ -263,21 +263,16 @@ common stylishHaskell if flag(stylishHaskell) || flag(all-formatters)- hs-source-dirs: plugins/default/src- other-modules: Ide.Plugin.StylishHaskell- build-depends: stylish-haskell ^>=0.12+ build-depends: hls-stylish-haskell-plugin ^>= 1.0.0.0 cpp-options: -DstylishHaskell common brittany- if (flag(brittany) || flag(all-formatters)) && flag(agpl)- hs-source-dirs: plugins/default/src- other-modules: Ide.Plugin.Brittany- build-depends: brittany >= 0.13.1.0+ if (flag(brittany) || flag(all-formatters))+ build-depends: hls-brittany-plugin ^>= 1.0.0.1 cpp-options: -Dbrittany executable haskell-language-server- import: agpl- , common-deps+ import: common-deps -- plugins , example-plugins , class@@ -337,19 +332,18 @@ , mtl , regex-tdfa , safe-exceptions- , shake >=0.17.5+ , shake , sqlite-simple , temporary , transformers , unordered-containers- , with-utf8 include-dirs: include default-language: Haskell2010 default-extensions: DataKinds, TypeOperators executable haskell-language-server-wrapper- import: agpl, common-deps+ import: common-deps main-is: Wrapper.hs hs-source-dirs: exe other-modules: Paths_haskell_language_server@@ -378,43 +372,9 @@ default-language: Haskell2010 --- This common stanza simulates a previous private lib--- We removed it due to issues with stack when loading the project using a stack based hie.yaml--- See https://github.com/haskell/haskell-language-server/issues/114-common hls-test-utils- import: agpl, common-deps- hs-source-dirs: test/utils- other-modules: Test.Hls.Util- build-depends:- , aeson- , blaze-markup- , containers- , data-default- , lsp- , hie-bios- , hls-plugin-api ^>= 1.0.0.0- , hslogger- , hspec- , hspec-core- , lens- , lsp-test == 0.13.0.0- , stm- , tasty-expected-failure- , tasty-hunit- , temporary- , transformers- , unordered-containers- , yaml - ghc-options: -Wall -Wredundant-constraints-- if flag(pedantic)- ghc-options: -Werror-- default-language: Haskell2010- test-suite func-test- import: agpl, common-deps, hls-test-utils+ import: common-deps type: exitcode-stdio-1.0 default-language: Haskell2010 build-tool-depends:@@ -426,26 +386,25 @@ , data-default , hspec-expectations , lens- , tasty- , tasty-ant-xml >=1.1.6- , tasty-golden- , tasty-rerun- , megaparsec- , deepseq , ghcide+ , hls-test-utils ^>= 1.0.0.0+ , lsp-types+ , aeson+ , hls-plugin-api+ , lsp-test+ , containers+ , unordered-containers - hs-source-dirs: test/functional plugins/hls-eval-plugin/test plugins/hls-splice-plugin/src plugins/hls-eval-plugin/src+ hs-source-dirs: test/functional test/utils main-is: Main.hs other-modules:- Class Command Completion Config Deferred Definition Diagnostic- Eval Format FunctionalBadProject FunctionalCodeAction@@ -458,10 +417,7 @@ Rename Symbol TypeDefinition- Splice- HaddockComments- Ide.Plugin.Splice.Types- Ide.Plugin.Eval.Types+ Test.Hls.Command default-extensions: OverloadedStrings ghc-options:@@ -471,7 +427,6 @@ ghc-options: -Werror -Wredundant-constraints test-suite wrapper-test- import: agpl, hls-test-utils type: exitcode-stdio-1.0 build-tool-depends: haskell-language-server:haskell-language-server-wrapper -any@@ -481,9 +436,8 @@ , base , directory , process- , tasty- , tasty-ant-xml >=1.1.6- , tasty-rerun+ , hls-test-utils+ , extra hs-source-dirs: test/wrapper main-is: Main.hs
@@ -1,10 +1,10 @@-#ifndef GHC_API_VERSION_H -#define GHC_API_VERSION_H - -#ifdef GHC_LIB -#define MIN_GHC_API_VERSION(x,y,z) MIN_VERSION_ghc_lib(x,y,z) -#else -#define MIN_GHC_API_VERSION(x,y,z) MIN_VERSION_ghc(x,y,z) -#endif - -#endif +#ifndef GHC_API_VERSION_H+#define GHC_API_VERSION_H++#ifdef GHC_LIB+#define MIN_GHC_API_VERSION(x,y,z) MIN_VERSION_ghc_lib(x,y,z)+#else+#define MIN_GHC_API_VERSION(x,y,z) MIN_VERSION_ghc(x,y,z)+#endif++#endif
@@ -1,118 +0,0 @@-{-# LANGUAGE PolyKinds #-} -{-# LANGUAGE TypeFamilies #-} -module Ide.Plugin.Brittany where - -import Control.Exception (bracket_) -import Control.Lens -import Control.Monad.IO.Class -import Control.Monad.Trans.Maybe (MaybeT, runMaybeT) -import Data.Coerce -import Data.Maybe (mapMaybe, maybeToList) -import Data.Semigroup -import Data.Text (Text) -import qualified Data.Text as T -import Development.IDE hiding (pluginHandlers) -import Development.IDE.GHC.Compat (topDir, ModSummary(ms_hspp_opts)) -import qualified DynFlags as D -import qualified EnumSet as S -import GHC.LanguageExtensions.Type -import Language.Haskell.Brittany -import Language.LSP.Types as J -import qualified Language.LSP.Types.Lens as J -import Ide.PluginUtils -import Ide.Types -import System.FilePath -import System.Environment (setEnv, unsetEnv) - -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) - { pluginHandlers = mkFormattingHandlers provider - } - --- | Formatter provider of Brittany. --- Formats the given source in either a given Range or the whole Document. --- If the provider fails an error is returned that can be displayed to the user. -provider :: FormattingHandler IdeState -provider ide typ contents nfp opts = liftIO $ do - confFile <- getConfFile nfp - let (range, selectedContents) = case typ of - FormatText -> (fullRange contents, contents) - FormatRange r -> (normalize r, extractRange r contents) - (modsum, _) <- runAction "brittany" ide $ use_ GetModSummary nfp - let dflags = ms_hspp_opts modsum - let withRuntimeLibdir = bracket_ (setEnv key $ topDir dflags) (unsetEnv key) - where key = "GHC_EXACTPRINT_GHC_LIBDIR" - res <- withRuntimeLibdir $ formatText dflags confFile opts selectedContents - case res of - Left err -> return $ Left $ responseError (T.pack $ "brittanyCmd: " ++ unlines (map showErr err)) - Right newText -> return $ Right $ J.List [TextEdit range newText] - --- | Primitive to format text with the given option. --- May not throw exceptions but return a Left value. --- Errors may be presented to the user. -formatText - :: MonadIO m - => D.DynFlags - -> Maybe FilePath -- ^ Path to configs. If Nothing, default configs will be used. - -> FormattingOptions -- ^ Options for the formatter such as indentation. - -> Text -- ^ Text to format - -> m (Either [BrittanyError] Text) -- ^ Either formatted Text or a error from Brittany. -formatText df confFile opts text = - liftIO $ runBrittany tabSize df confFile text - where tabSize = opts ^. J.tabSize - --- | Recursively search in every directory of the given filepath for brittany.yaml. --- If no such file has been found, return Nothing. -getConfFile :: NormalizedFilePath -> IO (Maybe FilePath) -getConfFile = findLocalConfigPath . takeDirectory . fromNormalizedFilePath - --- | Run Brittany on the given text with the given tab size and --- a configuration path. If no configuration path is given, a --- default configuration is chosen. The configuration may overwrite --- tab size parameter. --- --- Returns either a list of Brittany Errors or the reformatted text. --- May not throw an exception. -runBrittany :: Int -- ^ tab size - -> D.DynFlags - -> Maybe FilePath -- ^ local config file - -> Text -- ^ text to format - -> IO (Either [BrittanyError] Text) -runBrittany tabSize df confPath text = do - let cfg = mempty - { _conf_layout = - mempty { _lconfig_indentAmount = opt (coerce tabSize) - } - , _conf_forward = - (mempty :: CForwardOptions Option) - { _options_ghc = opt (getExtensions df) - } - } - - config <- fromMaybeT (pure staticDefaultConfig) (readConfigsWithUserConfig cfg (maybeToList confPath)) - parsePrintModule config text - -fromMaybeT :: Monad m => m a -> MaybeT m a -> m a -fromMaybeT def act = runMaybeT act >>= maybe def return - -opt :: a -> Option a -opt = Option . Just - -showErr :: BrittanyError -> String -showErr (ErrorInput s) = s -showErr (ErrorMacroConfig err input) - = "Error: parse error in inline configuration: " ++ err ++ " in the string \"" ++ input ++ "\"." -showErr (ErrorUnusedComment s) = s -showErr (LayoutWarning s) = s -showErr (ErrorUnknownNode s _) = s -showErr ErrorOutputCheck = "Brittany error - invalid output" - -showExtension :: Extension -> Maybe String -showExtension Cpp = Just "-XCPP" --- Brittany chokes on parsing extensions that produce warnings -showExtension DatatypeContexts = Nothing -showExtension RecordPuns = Just "-XNamedFieldPuns" -showExtension other = Just $ "-X" ++ show other - -getExtensions :: D.DynFlags -> [String] -getExtensions = mapMaybe showExtension . S.toList . D.extensionFlags
@@ -1,234 +1,236 @@-{-# LANGUAGE ViewPatterns #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DuplicateRecordFields #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TupleSections #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE RecordWildCards #-} - -module Ide.Plugin.Example - ( - descriptor - ) where - -import Control.DeepSeq ( NFData ) -import Control.Monad.Trans.Maybe -import Data.Aeson -import Data.Binary -import Data.Functor -import qualified Data.HashMap.Strict as Map -import Data.Hashable -import qualified Data.Text as T -import Data.Typeable -import Development.IDE as D -import Development.IDE.GHC.Compat (ParsedModule(ParsedModule)) -import Development.IDE.Core.Rules (useE) -import Development.IDE.Core.Shake (getDiagnostics, getHiddenDiagnostics) -import GHC.Generics -import Ide.PluginUtils -import Ide.Types -import Language.LSP.Types -import Language.LSP.Server -import Text.Regex.TDFA.Text() -import Control.Monad.IO.Class - --- --------------------------------------------------------------------- - -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) - { pluginRules = exampleRules - , pluginCommands = [PluginCommand "codelens.todo" "example adding" addTodoCmd] - , pluginHandlers = mkPluginHandler STextDocumentCodeAction codeAction - <> mkPluginHandler STextDocumentCodeLens codeLens - <> mkPluginHandler STextDocumentHover hover - <> mkPluginHandler STextDocumentDocumentSymbol symbols - <> mkPluginHandler STextDocumentCompletion completion - } - --- --------------------------------------------------------------------- - -hover :: PluginMethodHandler IdeState TextDocumentHover -hover ide _ HoverParams{..} = liftIO $ request "Hover" blah (Right Nothing) foundHover ide TextDocumentPositionParams{..} - -blah :: NormalizedFilePath -> Position -> Action (Maybe (Maybe Range, [T.Text])) -blah _ (Position line col) - = return $ Just (Just (Range (Position line col) (Position (line+1) 0)), ["example hover 1\n"]) - --- --------------------------------------------------------------------- --- Generating Diagnostics via rules --- --------------------------------------------------------------------- - -data Example = Example - deriving (Eq, Show, Typeable, Generic) -instance Hashable Example -instance NFData Example -instance Binary Example - -type instance RuleResult Example = () - -exampleRules :: Rules () -exampleRules = do - define $ \Example file -> do - _pm <- getParsedModule file - let diag = mkDiag file "example" DsError (Range (Position 0 0) (Position 1 0)) "example diagnostic, hello world" - return ([diag], Just ()) - - action $ do - files <- getFilesOfInterest - void $ uses Example $ Map.keys files - -mkDiag :: NormalizedFilePath - -> DiagnosticSource - -> DiagnosticSeverity - -> Range - -> T.Text - -> FileDiagnostic -mkDiag file diagSource sev loc msg = (file, D.ShowDiag,) - Diagnostic - { _range = loc - , _severity = Just sev - , _source = Just diagSource - , _message = msg - , _code = Nothing - , _tags = Nothing - , _relatedInformation = Nothing - } - --- --------------------------------------------------------------------- --- code actions --- --------------------------------------------------------------------- - --- | Generate code actions. -codeAction :: PluginMethodHandler IdeState TextDocumentCodeAction -codeAction state _pid (CodeActionParams _ _ (TextDocumentIdentifier uri) _range CodeActionContext{_diagnostics=List _xs}) = liftIO $ do - let Just nfp = uriToNormalizedFilePath $ toNormalizedUri uri - Just (ParsedModule{},_) <- runIdeAction "example" (shakeExtras state) $ useWithStaleFast GetParsedModule nfp - let - title = "Add TODO Item 1" - tedit = [TextEdit (Range (Position 2 0) (Position 2 0)) - "-- TODO1 added by Example Plugin directly\n"] - edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing - pure $ Right $ List - [ InR $ CodeAction title (Just CodeActionQuickFix) (Just $ List []) Nothing Nothing (Just edit) Nothing] - --- --------------------------------------------------------------------- - -codeLens :: PluginMethodHandler IdeState TextDocumentCodeLens -codeLens ideState plId CodeLensParams{_textDocument=TextDocumentIdentifier uri} = liftIO $ do - logInfo (ideLogger ideState) "Example.codeLens entered (ideLogger)" -- AZ - case uriToFilePath' uri of - Just (toNormalizedFilePath -> filePath) -> do - _ <- runIdeAction "Example.codeLens" (shakeExtras ideState) $ runMaybeT $ useE TypeCheck filePath - _diag <- getDiagnostics ideState - _hDiag <- getHiddenDiagnostics ideState - let - title = "Add TODO Item via Code Lens" - -- tedit = [TextEdit (Range (Position 3 0) (Position 3 0)) - -- "-- TODO added by Example Plugin via code lens action\n"] - -- edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing - range = Range (Position 3 0) (Position 4 0) - let cmdParams = AddTodoParams uri "do abc" - cmd = mkLspCommand plId "codelens.todo" title (Just [toJSON cmdParams]) - pure $ Right $ List [ CodeLens range (Just cmd) Nothing ] - Nothing -> pure $ Right $ List [] - --- --------------------------------------------------------------------- --- | Parameters for the addTodo PluginCommand. -data AddTodoParams = AddTodoParams - { file :: Uri -- ^ Uri of the file to add the pragma to - , todoText :: T.Text - } - deriving (Show, Eq, Generic, ToJSON, FromJSON) - -addTodoCmd :: CommandFunction IdeState AddTodoParams -addTodoCmd _ide (AddTodoParams uri todoText) = do - let - pos = Position 3 0 - textEdits = List - [TextEdit (Range pos pos) - ("-- TODO:" <> todoText <> "\n") - ] - res = WorkspaceEdit - (Just $ Map.singleton uri textEdits) - Nothing - _ <- sendRequest SWorkspaceApplyEdit (ApplyWorkspaceEditParams Nothing res) (\_ -> pure ()) - return $ Right Null - --- --------------------------------------------------------------------- - -foundHover :: (Maybe Range, [T.Text]) -> Either ResponseError (Maybe Hover) -foundHover (mbRange, contents) = - Right $ Just $ Hover (HoverContents $ MarkupContent MkMarkdown - $ T.intercalate sectionSeparator contents) mbRange - - --- | Respond to and log a hover or go-to-definition request -request - :: T.Text - -> (NormalizedFilePath -> Position -> Action (Maybe a)) - -> Either ResponseError b - -> (a -> Either ResponseError b) - -> IdeState - -> TextDocumentPositionParams - -> IO (Either ResponseError b) -request label getResults notFound found ide (TextDocumentPositionParams (TextDocumentIdentifier uri) pos) = do - mbResult <- case uriToFilePath' uri of - Just path -> logAndRunRequest label getResults ide pos path - Nothing -> pure Nothing - pure $ maybe notFound found mbResult - -logAndRunRequest :: T.Text -> (NormalizedFilePath -> Position -> Action b) - -> IdeState -> Position -> String -> IO b -logAndRunRequest label getResults ide pos path = do - let filePath = toNormalizedFilePath path - logInfo (ideLogger ide) $ - label <> " request at position " <> T.pack (showPosition pos) <> - " in file: " <> T.pack path - runAction "Example" ide $ getResults filePath pos - --- --------------------------------------------------------------------- - -symbols :: PluginMethodHandler IdeState TextDocumentDocumentSymbol -symbols _ide _pid (DocumentSymbolParams _ _ _doc) - = pure $ Right $ InL $ List [r] - where - r = DocumentSymbol name detail kind deprecation range selR chList - name = "Example_symbol_name" - detail = Nothing - kind = SkVariable - deprecation = Nothing - range = Range (Position 2 0) (Position 2 5) - selR = range - chList = Nothing - --- --------------------------------------------------------------------- - -completion :: PluginMethodHandler IdeState TextDocumentCompletion -completion _ide _pid (CompletionParams _doc _pos _ _ _mctxt) - = pure $ Right $ InL $ List [r] - where - r = CompletionItem label kind tags detail documentation deprecated preselect - sortText filterText insertText insertTextFormat - textEdit additionalTextEdits commitCharacters - command xd - label = "Example completion" - kind = Nothing - tags = Nothing - detail = Nothing - documentation = Nothing - deprecated = Nothing - preselect = Nothing - sortText = Nothing - filterText = Nothing - insertText = Nothing - insertTextFormat = Nothing - textEdit = Nothing - additionalTextEdits = Nothing - commitCharacters = Nothing - command = Nothing - xd = Nothing - --- --------------------------------------------------------------------- +{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ViewPatterns #-}++module Ide.Plugin.Example+ (+ descriptor+ ) where++import Control.DeepSeq (NFData)+import Control.Monad.IO.Class+import Control.Monad.Trans.Maybe+import Data.Aeson+import Data.Binary+import Data.Functor+import qualified Data.HashMap.Strict as Map+import Data.Hashable+import qualified Data.Text as T+import Data.Typeable+import Development.IDE as D+import Development.IDE.Core.Shake (getDiagnostics,+ getHiddenDiagnostics)+import Development.IDE.GHC.Compat (ParsedModule (ParsedModule))+import GHC.Generics+import Ide.PluginUtils+import Ide.Types+import Language.LSP.Server+import Language.LSP.Types+import Text.Regex.TDFA.Text ()++-- ---------------------------------------------------------------------++descriptor :: PluginId -> PluginDescriptor IdeState+descriptor plId = (defaultPluginDescriptor plId)+ { pluginRules = exampleRules+ , pluginCommands = [PluginCommand "codelens.todo" "example adding" addTodoCmd]+ , pluginHandlers = mkPluginHandler STextDocumentCodeAction codeAction+ <> mkPluginHandler STextDocumentCodeLens codeLens+ <> mkPluginHandler STextDocumentHover hover+ <> mkPluginHandler STextDocumentDocumentSymbol symbols+ <> mkPluginHandler STextDocumentCompletion completion+ }++-- ---------------------------------------------------------------------++hover :: PluginMethodHandler IdeState TextDocumentHover+hover ide _ HoverParams{..} = liftIO $ request "Hover" blah (Right Nothing) foundHover ide TextDocumentPositionParams{..}++blah :: NormalizedFilePath -> Position -> Action (Maybe (Maybe Range, [T.Text]))+blah _ (Position line col)+ = return $ Just (Just (Range (Position line col) (Position (line+1) 0)), ["example hover 1\n"])++-- ---------------------------------------------------------------------+-- Generating Diagnostics via rules+-- ---------------------------------------------------------------------++data Example = Example+ deriving (Eq, Show, Typeable, Generic)+instance Hashable Example+instance NFData Example+instance Binary Example++type instance RuleResult Example = ()++exampleRules :: Rules ()+exampleRules = do+ define $ \Example file -> do+ _pm <- getParsedModule file+ let diag = mkDiag file "example" DsError (Range (Position 0 0) (Position 1 0)) "example diagnostic, hello world"+ return ([diag], Just ())++ action $ do+ files <- getFilesOfInterest+ void $ uses Example $ Map.keys files++mkDiag :: NormalizedFilePath+ -> DiagnosticSource+ -> DiagnosticSeverity+ -> Range+ -> T.Text+ -> FileDiagnostic+mkDiag file diagSource sev loc msg = (file, D.ShowDiag,)+ Diagnostic+ { _range = loc+ , _severity = Just sev+ , _source = Just diagSource+ , _message = msg+ , _code = Nothing+ , _tags = Nothing+ , _relatedInformation = Nothing+ }++-- ---------------------------------------------------------------------+-- code actions+-- ---------------------------------------------------------------------++-- | Generate code actions.+codeAction :: PluginMethodHandler IdeState TextDocumentCodeAction+codeAction state _pid (CodeActionParams _ _ (TextDocumentIdentifier uri) _range CodeActionContext{_diagnostics=List _xs}) = liftIO $ do+ let Just nfp = uriToNormalizedFilePath $ toNormalizedUri uri+ Just (ParsedModule{},_) <- runIdeAction "example" (shakeExtras state) $ useWithStaleFast GetParsedModule nfp+ let+ title = "Add TODO Item 1"+ tedit = [TextEdit (Range (Position 2 0) (Position 2 0))+ "-- TODO1 added by Example Plugin directly\n"]+ edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing Nothing+ pure $ Right $ List+ [ InR $ CodeAction title (Just CodeActionQuickFix) (Just $ List []) Nothing Nothing (Just edit) Nothing Nothing]++-- ---------------------------------------------------------------------++codeLens :: PluginMethodHandler IdeState TextDocumentCodeLens+codeLens ideState plId CodeLensParams{_textDocument=TextDocumentIdentifier uri} = liftIO $ do+ logInfo (ideLogger ideState) "Example.codeLens entered (ideLogger)" -- AZ+ case uriToFilePath' uri of+ Just (toNormalizedFilePath -> filePath) -> do+ _ <- runIdeAction "Example.codeLens" (shakeExtras ideState) $ runMaybeT $ useE TypeCheck filePath+ _diag <- getDiagnostics ideState+ _hDiag <- getHiddenDiagnostics ideState+ let+ title = "Add TODO Item via Code Lens"+ -- tedit = [TextEdit (Range (Position 3 0) (Position 3 0))+ -- "-- TODO added by Example Plugin via code lens action\n"]+ -- edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing+ range = Range (Position 3 0) (Position 4 0)+ let cmdParams = AddTodoParams uri "do abc"+ cmd = mkLspCommand plId "codelens.todo" title (Just [toJSON cmdParams])+ pure $ Right $ List [ CodeLens range (Just cmd) Nothing ]+ Nothing -> pure $ Right $ List []++-- ---------------------------------------------------------------------+-- | Parameters for the addTodo PluginCommand.+data AddTodoParams = AddTodoParams+ { file :: Uri -- ^ Uri of the file to add the pragma to+ , todoText :: T.Text+ }+ deriving (Show, Eq, Generic, ToJSON, FromJSON)++addTodoCmd :: CommandFunction IdeState AddTodoParams+addTodoCmd _ide (AddTodoParams uri todoText) = do+ let+ pos = Position 3 0+ textEdits = List+ [TextEdit (Range pos pos)+ ("-- TODO:" <> todoText <> "\n")+ ]+ res = WorkspaceEdit+ (Just $ Map.singleton uri textEdits)+ Nothing+ Nothing+ _ <- sendRequest SWorkspaceApplyEdit (ApplyWorkspaceEditParams Nothing res) (\_ -> pure ())+ return $ Right Null++-- ---------------------------------------------------------------------++foundHover :: (Maybe Range, [T.Text]) -> Either ResponseError (Maybe Hover)+foundHover (mbRange, contents) =+ Right $ Just $ Hover (HoverContents $ MarkupContent MkMarkdown+ $ T.intercalate sectionSeparator contents) mbRange+++-- | Respond to and log a hover or go-to-definition request+request+ :: T.Text+ -> (NormalizedFilePath -> Position -> Action (Maybe a))+ -> Either ResponseError b+ -> (a -> Either ResponseError b)+ -> IdeState+ -> TextDocumentPositionParams+ -> IO (Either ResponseError b)+request label getResults notFound found ide (TextDocumentPositionParams (TextDocumentIdentifier uri) pos) = do+ mbResult <- case uriToFilePath' uri of+ Just path -> logAndRunRequest label getResults ide pos path+ Nothing -> pure Nothing+ pure $ maybe notFound found mbResult++logAndRunRequest :: T.Text -> (NormalizedFilePath -> Position -> Action b)+ -> IdeState -> Position -> String -> IO b+logAndRunRequest label getResults ide pos path = do+ let filePath = toNormalizedFilePath path+ logInfo (ideLogger ide) $+ label <> " request at position " <> T.pack (showPosition pos) <>+ " in file: " <> T.pack path+ runAction "Example" ide $ getResults filePath pos++-- ---------------------------------------------------------------------++symbols :: PluginMethodHandler IdeState TextDocumentDocumentSymbol+symbols _ide _pid (DocumentSymbolParams _ _ _doc)+ = pure $ Right $ InL $ List [r]+ where+ r = DocumentSymbol name detail kind Nothing deprecation range selR chList+ name = "Example_symbol_name"+ detail = Nothing+ kind = SkVariable+ deprecation = Nothing+ range = Range (Position 2 0) (Position 2 5)+ selR = range+ chList = Nothing++-- ---------------------------------------------------------------------++completion :: PluginMethodHandler IdeState TextDocumentCompletion+completion _ide _pid (CompletionParams _doc _pos _ _ _mctxt)+ = pure $ Right $ InL $ List [r]+ where+ r = CompletionItem label kind tags detail documentation deprecated preselect+ sortText filterText insertText insertTextFormat insertTextMode+ textEdit additionalTextEdits commitCharacters+ command xd+ label = "Example completion"+ kind = Nothing+ tags = Nothing+ detail = Nothing+ documentation = Nothing+ deprecated = Nothing+ preselect = Nothing+ sortText = Nothing+ filterText = Nothing+ insertText = Nothing+ insertTextMode = Nothing+ insertTextFormat = Nothing+ textEdit = Nothing+ additionalTextEdits = Nothing+ commitCharacters = Nothing+ command = Nothing+ xd = Nothing++-- ---------------------------------------------------------------------
@@ -1,228 +1,229 @@-{-# LANGUAGE ViewPatterns #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DuplicateRecordFields #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TupleSections #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE RecordWildCards #-} - -module Ide.Plugin.Example2 - ( - descriptor - ) where - -import Control.DeepSeq (NFData) -import Control.Monad.Trans.Maybe -import Data.Aeson -import Data.Binary -import Data.Functor -import qualified Data.HashMap.Strict as Map -import Data.Hashable -import qualified Data.Text as T -import Data.Typeable -import Development.IDE as D -import Development.IDE.Core.Rules -import Development.IDE.Core.Shake -import GHC.Generics -import Ide.PluginUtils -import Ide.Types -import Language.LSP.Types -import Language.LSP.Server -import Text.Regex.TDFA.Text() -import Control.Monad.IO.Class - --- --------------------------------------------------------------------- - -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) - { pluginRules = exampleRules - , pluginCommands = [PluginCommand "codelens.todo" "example adding" addTodoCmd] - , pluginHandlers = mkPluginHandler STextDocumentCodeAction codeAction - <> mkPluginHandler STextDocumentCodeLens codeLens - <> mkPluginHandler STextDocumentHover hover - <> mkPluginHandler STextDocumentDocumentSymbol symbols - <> mkPluginHandler STextDocumentCompletion completion - } - --- --------------------------------------------------------------------- - -hover :: PluginMethodHandler IdeState TextDocumentHover -hover ide _ HoverParams{..} = liftIO $ request "Hover" blah (Right Nothing) foundHover ide TextDocumentPositionParams{..} - -blah :: NormalizedFilePath -> Position -> Action (Maybe (Maybe Range, [T.Text])) -blah _ (Position line col) - = return $ Just (Just (Range (Position line col) (Position (line+1) 0)), ["example hover 2\n"]) - --- --------------------------------------------------------------------- --- Generating Diagnostics via rules --- --------------------------------------------------------------------- - -data Example2 = Example2 - deriving (Eq, Show, Typeable, Generic) -instance Hashable Example2 -instance NFData Example2 -instance Binary Example2 - -type instance RuleResult Example2 = () - -exampleRules :: Rules () -exampleRules = do - define $ \Example2 file -> do - _pm <- getParsedModule file - let diag = mkDiag file "example2" DsError (Range (Position 0 0) (Position 1 0)) "example2 diagnostic, hello world" - return ([diag], Just ()) - - action $ do - files <- getFilesOfInterest - void $ uses Example2 $ Map.keys files - -mkDiag :: NormalizedFilePath - -> DiagnosticSource - -> DiagnosticSeverity - -> Range - -> T.Text - -> FileDiagnostic -mkDiag file diagSource sev loc msg = (file, D.ShowDiag,) - Diagnostic - { _range = loc - , _severity = Just sev - , _source = Just diagSource - , _message = msg - , _code = Nothing - , _tags = Nothing - , _relatedInformation = Nothing - } - --- --------------------------------------------------------------------- --- code actions --- --------------------------------------------------------------------- - --- | Generate code actions. -codeAction :: PluginMethodHandler IdeState TextDocumentCodeAction -codeAction _state _pid (CodeActionParams _ _ (TextDocumentIdentifier uri) _range CodeActionContext{_diagnostics=List _xs}) = do - let - title = "Add TODO2 Item" - tedit = [TextEdit (Range (Position 3 0) (Position 3 0)) - "-- TODO2 added by Example2 Plugin directly\n"] - edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing - pure $ Right $ List - [ InR $ CodeAction title (Just CodeActionQuickFix) (Just $ List []) Nothing Nothing (Just edit) Nothing ] - --- --------------------------------------------------------------------- - -codeLens :: PluginMethodHandler IdeState TextDocumentCodeLens -codeLens ideState plId CodeLensParams{_textDocument=TextDocumentIdentifier uri} = liftIO $ do - logInfo (ideLogger ideState) "Example2.codeLens entered (ideLogger)" -- AZ - case uriToFilePath' uri of - Just (toNormalizedFilePath -> filePath) -> do - _ <- runIdeAction (fromNormalizedFilePath filePath) (shakeExtras ideState) $ runMaybeT $ useE TypeCheck filePath - _diag <- getDiagnostics ideState - _hDiag <- getHiddenDiagnostics ideState - let - title = "Add TODO2 Item via Code Lens" - range = Range (Position 3 0) (Position 4 0) - let cmdParams = AddTodoParams uri "do abc" - cmd = mkLspCommand plId "codelens.todo" title (Just [toJSON cmdParams]) - pure $ Right $ List [ CodeLens range (Just cmd) Nothing ] - Nothing -> pure $ Right $ List [] - --- --------------------------------------------------------------------- --- | Parameters for the addTodo PluginCommand. -data AddTodoParams = AddTodoParams - { file :: Uri -- ^ Uri of the file to add the pragma to - , todoText :: T.Text - } - deriving (Show, Eq, Generic, ToJSON, FromJSON) - -addTodoCmd :: CommandFunction IdeState AddTodoParams -addTodoCmd _ide (AddTodoParams uri todoText) = do - let - pos = Position 5 0 - textEdits = List - [TextEdit (Range pos pos) - ("-- TODO2:" <> todoText <> "\n") - ] - res = WorkspaceEdit - (Just $ Map.singleton uri textEdits) - Nothing - _ <- sendRequest SWorkspaceApplyEdit (ApplyWorkspaceEditParams Nothing res) (\_ -> pure ()) - return $ Right Null - --- --------------------------------------------------------------------- - -foundHover :: (Maybe Range, [T.Text]) -> Either ResponseError (Maybe Hover) -foundHover (mbRange, contents) = - Right $ Just $ Hover (HoverContents $ MarkupContent MkMarkdown - $ T.intercalate sectionSeparator contents) mbRange - - --- | Respond to and log a hover or go-to-definition request -request - :: T.Text - -> (NormalizedFilePath -> Position -> Action (Maybe a)) - -> Either ResponseError b - -> (a -> Either ResponseError b) - -> IdeState - -> TextDocumentPositionParams - -> IO (Either ResponseError b) -request label getResults notFound found ide (TextDocumentPositionParams (TextDocumentIdentifier uri) pos) = do - mbResult <- case uriToFilePath' uri of - Just path -> logAndRunRequest label getResults ide pos path - Nothing -> pure Nothing - pure $ maybe notFound found mbResult - -logAndRunRequest :: T.Text -> (NormalizedFilePath -> Position -> Action b) - -> IdeState -> Position -> String -> IO b -logAndRunRequest label getResults ide pos path = do - let filePath = toNormalizedFilePath path - logInfo (ideLogger ide) $ - label <> " request at position " <> T.pack (showPosition pos) <> - " in file: " <> T.pack path - runAction "Example2" ide $ getResults filePath pos - --- --------------------------------------------------------------------- - -symbols :: PluginMethodHandler IdeState TextDocumentDocumentSymbol -symbols _ide _ (DocumentSymbolParams _ _ _doc) - = pure $ Right $ InL $ List [r] - where - r = DocumentSymbol name detail kind deprecation range selR chList - name = "Example2_symbol_name" - detail = Nothing - kind = SkVariable - deprecation = Nothing - range = Range (Position 4 1) (Position 4 7) - selR = range - chList = Nothing - --- --------------------------------------------------------------------- - -completion :: PluginMethodHandler IdeState TextDocumentCompletion -completion _ide _pid (CompletionParams _doc _pos _ _ _mctxt) - = pure $ Right $ InL $ List [r] - where - r = CompletionItem label kind tags detail documentation deprecated preselect - sortText filterText insertText insertTextFormat - textEdit additionalTextEdits commitCharacters - command xd - label = "Example2 completion" - kind = Nothing - tags = Nothing - detail = Nothing - documentation = Nothing - deprecated = Nothing - preselect = Nothing - sortText = Nothing - filterText = Nothing - insertText = Nothing - insertTextFormat = Nothing - textEdit = Nothing - additionalTextEdits = Nothing - commitCharacters = Nothing - command = Nothing - xd = Nothing - --- --------------------------------------------------------------------- +{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ViewPatterns #-}++module Ide.Plugin.Example2+ (+ descriptor+ ) where++import Control.DeepSeq (NFData)+import Control.Monad.IO.Class+import Control.Monad.Trans.Maybe+import Data.Aeson+import Data.Binary+import Data.Functor+import qualified Data.HashMap.Strict as Map+import Data.Hashable+import qualified Data.Text as T+import Data.Typeable+import Development.IDE as D+import Development.IDE.Core.Shake+import GHC.Generics+import Ide.PluginUtils+import Ide.Types+import Language.LSP.Server+import Language.LSP.Types+import Text.Regex.TDFA.Text ()++-- ---------------------------------------------------------------------++descriptor :: PluginId -> PluginDescriptor IdeState+descriptor plId = (defaultPluginDescriptor plId)+ { pluginRules = exampleRules+ , pluginCommands = [PluginCommand "codelens.todo" "example adding" addTodoCmd]+ , pluginHandlers = mkPluginHandler STextDocumentCodeAction codeAction+ <> mkPluginHandler STextDocumentCodeLens codeLens+ <> mkPluginHandler STextDocumentHover hover+ <> mkPluginHandler STextDocumentDocumentSymbol symbols+ <> mkPluginHandler STextDocumentCompletion completion+ }++-- ---------------------------------------------------------------------++hover :: PluginMethodHandler IdeState TextDocumentHover+hover ide _ HoverParams{..} = liftIO $ request "Hover" blah (Right Nothing) foundHover ide TextDocumentPositionParams{..}++blah :: NormalizedFilePath -> Position -> Action (Maybe (Maybe Range, [T.Text]))+blah _ (Position line col)+ = return $ Just (Just (Range (Position line col) (Position (line+1) 0)), ["example hover 2\n"])++-- ---------------------------------------------------------------------+-- Generating Diagnostics via rules+-- ---------------------------------------------------------------------++data Example2 = Example2+ deriving (Eq, Show, Typeable, Generic)+instance Hashable Example2+instance NFData Example2+instance Binary Example2++type instance RuleResult Example2 = ()++exampleRules :: Rules ()+exampleRules = do+ define $ \Example2 file -> do+ _pm <- getParsedModule file+ let diag = mkDiag file "example2" DsError (Range (Position 0 0) (Position 1 0)) "example2 diagnostic, hello world"+ return ([diag], Just ())++ action $ do+ files <- getFilesOfInterest+ void $ uses Example2 $ Map.keys files++mkDiag :: NormalizedFilePath+ -> DiagnosticSource+ -> DiagnosticSeverity+ -> Range+ -> T.Text+ -> FileDiagnostic+mkDiag file diagSource sev loc msg = (file, D.ShowDiag,)+ Diagnostic+ { _range = loc+ , _severity = Just sev+ , _source = Just diagSource+ , _message = msg+ , _code = Nothing+ , _tags = Nothing+ , _relatedInformation = Nothing+ }++-- ---------------------------------------------------------------------+-- code actions+-- ---------------------------------------------------------------------++-- | Generate code actions.+codeAction :: PluginMethodHandler IdeState TextDocumentCodeAction+codeAction _state _pid (CodeActionParams _ _ (TextDocumentIdentifier uri) _range CodeActionContext{_diagnostics=List _xs}) = do+ let+ title = "Add TODO2 Item"+ tedit = [TextEdit (Range (Position 3 0) (Position 3 0))+ "-- TODO2 added by Example2 Plugin directly\n"]+ edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing Nothing+ pure $ Right $ List+ [ InR $ CodeAction title (Just CodeActionQuickFix) (Just $ List []) Nothing Nothing (Just edit) Nothing Nothing]++-- ---------------------------------------------------------------------++codeLens :: PluginMethodHandler IdeState TextDocumentCodeLens+codeLens ideState plId CodeLensParams{_textDocument=TextDocumentIdentifier uri} = liftIO $ do+ logInfo (ideLogger ideState) "Example2.codeLens entered (ideLogger)" -- AZ+ case uriToFilePath' uri of+ Just (toNormalizedFilePath -> filePath) -> do+ _ <- runIdeAction (fromNormalizedFilePath filePath) (shakeExtras ideState) $ runMaybeT $ useE TypeCheck filePath+ _diag <- getDiagnostics ideState+ _hDiag <- getHiddenDiagnostics ideState+ let+ title = "Add TODO2 Item via Code Lens"+ range = Range (Position 3 0) (Position 4 0)+ let cmdParams = AddTodoParams uri "do abc"+ cmd = mkLspCommand plId "codelens.todo" title (Just [toJSON cmdParams])+ pure $ Right $ List [ CodeLens range (Just cmd) Nothing ]+ Nothing -> pure $ Right $ List []++-- ---------------------------------------------------------------------+-- | Parameters for the addTodo PluginCommand.+data AddTodoParams = AddTodoParams+ { file :: Uri -- ^ Uri of the file to add the pragma to+ , todoText :: T.Text+ }+ deriving (Show, Eq, Generic, ToJSON, FromJSON)++addTodoCmd :: CommandFunction IdeState AddTodoParams+addTodoCmd _ide (AddTodoParams uri todoText) = do+ let+ pos = Position 5 0+ textEdits = List+ [TextEdit (Range pos pos)+ ("-- TODO2:" <> todoText <> "\n")+ ]+ res = WorkspaceEdit+ (Just $ Map.singleton uri textEdits)+ Nothing+ Nothing+ _ <- sendRequest SWorkspaceApplyEdit (ApplyWorkspaceEditParams Nothing res) (\_ -> pure ())+ return $ Right Null++-- ---------------------------------------------------------------------++foundHover :: (Maybe Range, [T.Text]) -> Either ResponseError (Maybe Hover)+foundHover (mbRange, contents) =+ Right $ Just $ Hover (HoverContents $ MarkupContent MkMarkdown+ $ T.intercalate sectionSeparator contents) mbRange+++-- | Respond to and log a hover or go-to-definition request+request+ :: T.Text+ -> (NormalizedFilePath -> Position -> Action (Maybe a))+ -> Either ResponseError b+ -> (a -> Either ResponseError b)+ -> IdeState+ -> TextDocumentPositionParams+ -> IO (Either ResponseError b)+request label getResults notFound found ide (TextDocumentPositionParams (TextDocumentIdentifier uri) pos) = do+ mbResult <- case uriToFilePath' uri of+ Just path -> logAndRunRequest label getResults ide pos path+ Nothing -> pure Nothing+ pure $ maybe notFound found mbResult++logAndRunRequest :: T.Text -> (NormalizedFilePath -> Position -> Action b)+ -> IdeState -> Position -> String -> IO b+logAndRunRequest label getResults ide pos path = do+ let filePath = toNormalizedFilePath path+ logInfo (ideLogger ide) $+ label <> " request at position " <> T.pack (showPosition pos) <>+ " in file: " <> T.pack path+ runAction "Example2" ide $ getResults filePath pos++-- ---------------------------------------------------------------------++symbols :: PluginMethodHandler IdeState TextDocumentDocumentSymbol+symbols _ide _ (DocumentSymbolParams _ _ _doc)+ = pure $ Right $ InL $ List [r]+ where+ r = DocumentSymbol name detail kind Nothing deprecation range selR chList+ name = "Example2_symbol_name"+ detail = Nothing+ kind = SkVariable+ deprecation = Nothing+ range = Range (Position 4 1) (Position 4 7)+ selR = range+ chList = Nothing++-- ---------------------------------------------------------------------++completion :: PluginMethodHandler IdeState TextDocumentCompletion+completion _ide _pid (CompletionParams _doc _pos _ _ _mctxt)+ = pure $ Right $ InL $ List [r]+ where+ r = CompletionItem label kind tags detail documentation deprecated preselect+ sortText filterText insertText insertTextFormat insertTextMode+ textEdit additionalTextEdits commitCharacters+ command xd+ label = "Example2 completion"+ kind = Nothing+ tags = Nothing+ detail = Nothing+ documentation = Nothing+ deprecated = Nothing+ preselect = Nothing+ sortText = Nothing+ filterText = Nothing+ insertText = Nothing+ insertTextMode = Nothing+ insertTextFormat = Nothing+ textEdit = Nothing+ additionalTextEdits = Nothing+ commitCharacters = Nothing+ command = Nothing+ xd = Nothing++-- ---------------------------------------------------------------------
@@ -1,59 +1,59 @@-{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ScopedTypeVariables #-} - -module Ide.Plugin.Floskell - ( - descriptor - , provider - ) -where - -import qualified Data.ByteString.Lazy as BS -import qualified Data.Text as T -import qualified Data.Text.Encoding as T -import Development.IDE as D hiding (pluginHandlers) -import Floskell -import Ide.PluginUtils -import Ide.Types -import Language.LSP.Types -import Text.Regex.TDFA.Text() -import Control.Monad.IO.Class - --- --------------------------------------------------------------------- - -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) - { pluginHandlers = mkFormattingHandlers provider - } - --- --------------------------------------------------------------------- - --- | Format provider of Floskell. --- Formats the given source in either a given Range or the whole Document. --- If the provider fails an error is returned that can be displayed to the user. -provider :: FormattingHandler IdeState -provider _ideState typ contents fp _ = liftIO $ do - let file = fromNormalizedFilePath fp - config <- findConfigOrDefault file - let (range, selectedContents) = case typ of - FormatText -> (fullRange contents, contents) - FormatRange r -> (r, extractRange r contents) - result = reformat config (Just file) (BS.fromStrict (T.encodeUtf8 selectedContents)) - case result of - Left err -> return $ Left $ responseError (T.pack $ "floskellCmd: " ++ err) - Right new -> return $ Right $ List [TextEdit range (T.decodeUtf8 (BS.toStrict new))] - --- | Find Floskell Config, user and system wide or provides a default style. --- Every directory of the filepath will be searched to find a user configuration. --- Also looks into places such as XDG_CONFIG_DIRECTORY<https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html>. --- This function may not throw an exception and returns a default config. -findConfigOrDefault :: FilePath -> IO AppConfig -findConfigOrDefault file = do - mbConf <- findAppConfigIn file - case mbConf of - Just confFile -> readAppConfig confFile - Nothing -> - let gibiansky = head (filter (\s -> styleName s == "gibiansky") styles) - in return $ defaultAppConfig { appStyle = gibiansky } - --- --------------------------------------------------------------------- +{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Ide.Plugin.Floskell+ (+ descriptor+ , provider+ )+where++import Control.Monad.IO.Class+import qualified Data.ByteString.Lazy as BS+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import Development.IDE as D hiding (pluginHandlers)+import Floskell+import Ide.PluginUtils+import Ide.Types+import Language.LSP.Types+import Text.Regex.TDFA.Text ()++-- ---------------------------------------------------------------------++descriptor :: PluginId -> PluginDescriptor IdeState+descriptor plId = (defaultPluginDescriptor plId)+ { pluginHandlers = mkFormattingHandlers provider+ }++-- ---------------------------------------------------------------------++-- | Format provider of Floskell.+-- Formats the given source in either a given Range or the whole Document.+-- If the provider fails an error is returned that can be displayed to the user.+provider :: FormattingHandler IdeState+provider _ideState typ contents fp _ = liftIO $ do+ let file = fromNormalizedFilePath fp+ config <- findConfigOrDefault file+ let (range, selectedContents) = case typ of+ FormatText -> (fullRange contents, contents)+ FormatRange r -> (r, extractRange r contents)+ result = reformat config (Just file) (BS.fromStrict (T.encodeUtf8 selectedContents))+ case result of+ Left err -> return $ Left $ responseError (T.pack $ "floskellCmd: " ++ err)+ Right new -> return $ Right $ List [TextEdit range (T.decodeUtf8 (BS.toStrict new))]++-- | Find Floskell Config, user and system wide or provides a default style.+-- Every directory of the filepath will be searched to find a user configuration.+-- Also looks into places such as XDG_CONFIG_DIRECTORY<https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html>.+-- This function may not throw an exception and returns a default config.+findConfigOrDefault :: FilePath -> IO AppConfig+findConfigOrDefault file = do+ mbConf <- findAppConfigIn file+ case mbConf of+ Just confFile -> readAppConfig confFile+ Nothing ->+ let gibiansky = head (filter (\s -> styleName s == "gibiansky") styles)+ in return $ defaultAppConfig { appStyle = gibiansky }++-- ---------------------------------------------------------------------
@@ -1,103 +1,103 @@-{-# LANGUAGE DisambiguateRecordFields #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE PackageImports #-} -{-# LANGUAGE TypeApplications #-} - -module Ide.Plugin.Fourmolu ( - descriptor, - provider, -) where - -import Control.Exception -import Data.Either.Extra -import System.FilePath - -import Control.Lens ((^.)) -import qualified Data.Text as T -import Development.IDE as D hiding (pluginHandlers) -import qualified DynFlags as D -import qualified EnumSet as S -import GHC (DynFlags, moduleNameString) -import GHC.LanguageExtensions.Type (Extension (Cpp)) -import GhcPlugins (HscEnv (hsc_dflags)) -import Ide.PluginUtils (makeDiffTextEdit) - -import Ide.Types -import Language.LSP.Server -import Language.LSP.Types -import Language.LSP.Types.Lens -import "fourmolu" Ormolu -import Control.Monad.IO.Class - --- --------------------------------------------------------------------- - -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = - (defaultPluginDescriptor plId) - { pluginHandlers = mkFormattingHandlers provider - } - --- --------------------------------------------------------------------- - -provider :: FormattingHandler IdeState -provider ideState typ contents fp fo = withIndefiniteProgress title Cancellable $ do - ghc <- liftIO $ runAction "Fourmolu" ideState $ use GhcSession fp - fileOpts <- case hsc_dflags . hscEnv <$> ghc of - Nothing -> return [] - Just df -> liftIO $ convertDynFlags df - - let format printerOpts = - mapLeft (responseError . ("Fourmolu: " <>) . T.pack . show) - <$> try @OrmoluException (makeDiffTextEdit contents <$> ormolu config fp' (T.unpack contents)) - where - config = - defaultConfig - { cfgDynOptions = fileOpts - , cfgRegion = region - , cfgDebug = True - , cfgPrinterOpts = - fillMissingPrinterOpts - (printerOpts <> lspPrinterOpts) - defaultPrinterOpts - } - - liftIO (loadConfigFile fp') >>= \case - ConfigLoaded file opts -> liftIO $ do - putStrLn $ "Loaded Fourmolu config from: " <> file - format opts - ConfigNotFound searchDirs -> liftIO $ do - putStrLn - . unlines - $ ("No " ++ show configFileName ++ " found in any of:") : - map (" " ++) searchDirs - format mempty - ConfigParseError f (_, err) -> do - sendNotification SWindowShowMessage $ - ShowMessageParams - { _xtype = MtError - , _message = errorMessage - } - return . Left $ responseError errorMessage - where - errorMessage = "Failed to load " <> T.pack f <> ": " <> T.pack err - where - fp' = fromNormalizedFilePath fp - title = "Formatting " <> T.pack (takeFileName fp') - lspPrinterOpts = mempty{poIndentation = Just $ fo ^. tabSize} - region = case typ of - FormatText -> - RegionIndices Nothing Nothing - FormatRange (Range (Position sl _) (Position el _)) -> - RegionIndices (Just $ sl + 1) (Just $ el + 1) - -convertDynFlags :: DynFlags -> IO [DynOption] -convertDynFlags df = - let pp = ["-pgmF=" <> p | not (null p)] - p = D.sPgm_F $ D.settings df - pm = map (("-fplugin=" <>) . moduleNameString) $ D.pluginModNames df - ex = map showExtension $ S.toList $ D.extensionFlags df - showExtension = \case - Cpp -> "-XCPP" - x -> "-X" ++ show x - in return $ map DynOption $ pp <> pm <> ex +{-# LANGUAGE DisambiguateRecordFields #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE TypeApplications #-}++module Ide.Plugin.Fourmolu (+ descriptor,+ provider,+) where++import Control.Exception+import Data.Either.Extra+import System.FilePath++import Control.Lens ((^.))+import qualified Data.Text as T+import Development.IDE as D hiding (pluginHandlers)+import qualified DynFlags as D+import qualified EnumSet as S+import GHC (DynFlags, moduleNameString)+import GHC.LanguageExtensions.Type (Extension (Cpp))+import GhcPlugins (HscEnv (hsc_dflags))+import Ide.PluginUtils (makeDiffTextEdit)++import Control.Monad.IO.Class+import Ide.Types+import Language.LSP.Server hiding (defaultConfig)+import Language.LSP.Types+import Language.LSP.Types.Lens+import "fourmolu" Ormolu++-- ---------------------------------------------------------------------++descriptor :: PluginId -> PluginDescriptor IdeState+descriptor plId =+ (defaultPluginDescriptor plId)+ { pluginHandlers = mkFormattingHandlers provider+ }++-- ---------------------------------------------------------------------++provider :: FormattingHandler IdeState+provider ideState typ contents fp fo = withIndefiniteProgress title Cancellable $ do+ ghc <- liftIO $ runAction "Fourmolu" ideState $ use GhcSession fp+ fileOpts <- case hsc_dflags . hscEnv <$> ghc of+ Nothing -> return []+ Just df -> liftIO $ convertDynFlags df++ let format printerOpts =+ mapLeft (responseError . ("Fourmolu: " <>) . T.pack . show)+ <$> try @OrmoluException (makeDiffTextEdit contents <$> ormolu config fp' (T.unpack contents))+ where+ config =+ defaultConfig+ { cfgDynOptions = fileOpts+ , cfgRegion = region+ , cfgDebug = True+ , cfgPrinterOpts =+ fillMissingPrinterOpts+ (printerOpts <> lspPrinterOpts)+ defaultPrinterOpts+ }++ liftIO (loadConfigFile fp') >>= \case+ ConfigLoaded file opts -> liftIO $ do+ putStrLn $ "Loaded Fourmolu config from: " <> file+ format opts+ ConfigNotFound searchDirs -> liftIO $ do+ putStrLn+ . unlines+ $ ("No " ++ show configFileName ++ " found in any of:") :+ map (" " ++) searchDirs+ format mempty+ ConfigParseError f (_, err) -> do+ sendNotification SWindowShowMessage $+ ShowMessageParams+ { _xtype = MtError+ , _message = errorMessage+ }+ return . Left $ responseError errorMessage+ where+ errorMessage = "Failed to load " <> T.pack f <> ": " <> T.pack err+ where+ fp' = fromNormalizedFilePath fp+ title = "Formatting " <> T.pack (takeFileName fp')+ lspPrinterOpts = mempty{poIndentation = Just $ fo ^. tabSize}+ region = case typ of+ FormatText ->+ RegionIndices Nothing Nothing+ FormatRange (Range (Position sl _) (Position el _)) ->+ RegionIndices (Just $ sl + 1) (Just $ el + 1)++convertDynFlags :: DynFlags -> IO [DynOption]+convertDynFlags df =+ let pp = ["-pgmF=" <> p | not (null p)]+ p = D.sPgm_F $ D.settings df+ pm = map (("-fplugin=" <>) . moduleNameString) $ D.pluginModNames df+ ex = map showExtension $ S.toList $ D.extensionFlags df+ showExtension = \case+ Cpp -> "-XCPP"+ x -> "-X" ++ show x+ in return $ map DynOption $ pp <> pm <> ex
@@ -1,178 +1,157 @@-{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE NoMonomorphismRestriction #-} -{-# OPTIONS_GHC -Wall -Wwarn -fno-warn-type-defaults -fno-warn-unused-binds -fno-warn-unused-imports -Wno-unticked-promoted-constructors #-} - -{- | Keep the module name in sync with its file path. - -Provide CodeLenses to: -* Add a module header ("module /moduleName/ where") to empty Haskell files -* Fix the module name if incorrect --} -module Ide.Plugin.ModuleName ( - descriptor, -) where - -import Control.Monad.IO.Class (MonadIO (liftIO)) -import Control.Monad -import Data.Aeson ( - ToJSON (toJSON), - Value (Null), - ) -import Data.Char (isLower) -import qualified Data.HashMap.Strict as Map -import Data.List (find, intercalate, isPrefixOf) -import Data.Maybe (maybeToList) -import Data.String (IsString) -import Data.Text (Text, pack) -import qualified Data.Text as T --- import Debug.Trace (trace) -import Development.IDE ( - GetParsedModule ( - GetParsedModule - ), - GhcSession (GhcSession), - HscEnvEq, - IdeState, - List (..), - NormalizedFilePath, - Position (Position), - Range (Range), - evalGhcEnv, - hscEnvWithImportPaths, - realSrcSpanToRange, - runAction, - toNormalizedUri, - uriToFilePath', - use, - use_, - ) -import GHC ( - DynFlags (importPaths), - GenLocated (L), - HsModule (hsmodName), - ParsedModule (pm_parsed_source), - SrcSpan (RealSrcSpan), - getSessionDynFlags, - unLoc, - ) -import Ide.PluginUtils (mkLspCmdId, getProcessID) -import Ide.Types -import Language.LSP.Server -import Language.LSP.Types -import Language.LSP.VFS (virtualFileText) -import System.Directory (canonicalizePath) -import System.FilePath ( - dropExtension, - splitDirectories, - takeFileName, - ) - --- |Plugin descriptor -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = - (defaultPluginDescriptor plId) - { pluginHandlers = mkPluginHandler STextDocumentCodeLens codeLens - , pluginCommands = [PluginCommand editCommandName editCommandName command] - } - -editCommandName :: IsString p => p -editCommandName = "edit" - -asCodeLens :: Text -> Action -> CodeLens -asCodeLens cid Replace{..} = - CodeLens - aRange - (Just $ Command aTitle cid (Just (List [toJSON aUri]))) - Nothing - --- | Generate code lenses -codeLens :: PluginMethodHandler IdeState TextDocumentCodeLens -codeLens state pluginId CodeLensParams{_textDocument=TextDocumentIdentifier uri} = do - do - pid <- liftIO $ pack . show <$> getProcessID - Right . List . maybeToList . (asCodeLens (mkLspCmdId pid pluginId editCommandName) <$>) <$> action state uri - --- | (Quasi) Idempotent command execution: recalculate action to execute on command request -command :: CommandFunction IdeState Uri -command state uri = do - actMaybe <- action state uri - case actMaybe of - Nothing -> pure () - Just act -> void $ sendRequest SWorkspaceApplyEdit (ApplyWorkspaceEditParams Nothing (asEdit act)) (\_ -> pure ()) - return (Right Null) - --- | A source code change -data Action = Replace {aUri :: Uri, aRange :: Range, aTitle :: Text, aCode :: Text} deriving (Show) - --- | Convert an Action to the corresponding edit operation -asEdit :: Action -> WorkspaceEdit -asEdit act@Replace{..} = - WorkspaceEdit (Just $ Map.singleton aUri $ List (asTextEdits act)) Nothing - -asTextEdits :: Action -> [TextEdit] -asTextEdits Replace{..} = [TextEdit aRange aCode] - --- | Required action (that can be converted to either CodeLenses or CodeActions) -action :: IdeState -> Uri -> LspM c (Maybe Action) -action state uri = - traceAs "action" <$> do - let Just nfp = uriToNormalizedFilePath $ toNormalizedUri uri - let Just fp = uriToFilePath' uri - - contents <- getVirtualFile $ toNormalizedUri uri - let emptyModule = maybe True (T.null . T.strip . virtualFileText) contents - - correctNameMaybe <- liftIO $ traceAs "correctName" <$> pathModuleName state nfp fp - statedNameMaybe <- liftIO $ traceAs "statedName" <$> codeModuleName state nfp - - let act = Replace uri - let todo = case (correctNameMaybe, statedNameMaybe) of - (Just correctName, Just (nameRange, statedName)) - | correctName /= statedName -> - Just $ - act - nameRange - ("Set module name to " <> correctName) - correctName - (Just correctName, _) - | emptyModule -> - let code = T.unwords ["module", correctName, "where\n"] - in Just $ act (Range (Position 0 0) (Position 0 0)) code code - _ -> Nothing - return todo - --- | The module name, as derived by the position of the module in its source directory -pathModuleName :: IdeState -> NormalizedFilePath -> String -> IO (Maybe Text) -pathModuleName state normFilePath filePath - | isLower (head $ takeFileName filePath) = return $ Just "Main" - | otherwise = do - session :: HscEnvEq <- runAction "ModuleName.ghcSession" state $ use_ GhcSession normFilePath - srcPaths <- evalGhcEnv (hscEnvWithImportPaths session) $ importPaths <$> getSessionDynFlags - paths <- mapM canonicalizePath srcPaths - mdlPath <- canonicalizePath filePath - let maybePrefix = find (`isPrefixOf` mdlPath) paths - - let maybeMdlName = - ( \prefix -> - intercalate "." - . splitDirectories - . drop (length prefix + 1) - $ dropExtension mdlPath - ) - <$> maybePrefix - return $ T.pack <$> maybeMdlName - --- | The module name, as stated in the module -codeModuleName :: IdeState -> NormalizedFilePath -> IO (Maybe (Range, Text)) -codeModuleName state nfp = - ((\(L (RealSrcSpan l) m) -> (realSrcSpanToRange l, T.pack . show $ m)) <$>) - . ((hsmodName . unLoc . pm_parsed_source) =<<) - <$> runAction "ModuleName.GetParsedModule" state (use GetParsedModule nfp) - --- traceAs :: Show a => String -> a -> a --- traceAs lbl a = trace (lbl ++ " = " ++ show a) a - -traceAs :: b -> a -> a -traceAs _ a = a +{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# OPTIONS_GHC -Wall -Wwarn -fno-warn-type-defaults -fno-warn-unused-binds -fno-warn-unused-imports -Wno-unticked-promoted-constructors #-}++{- | Keep the module name in sync with its file path.++Provide CodeLenses to:+* Add a module header ("module /moduleName/ where") to empty Haskell files+* Fix the module name if incorrect+-}+module Ide.Plugin.ModuleName (+ descriptor,+) where++import Control.Monad+import Control.Monad.IO.Class (MonadIO (liftIO))+import Data.Aeson (ToJSON (toJSON), Value (Null))+import Data.Char (isLower)+import qualified Data.HashMap.Strict as Map+import Data.List (find, intercalate, isPrefixOf)+import Data.Maybe (maybeToList)+import Data.String (IsString)+import Data.Text (Text, pack)+import qualified Data.Text as T+-- import Debug.Trace (trace)+import Development.IDE (GetParsedModule (GetParsedModule),+ GhcSession (GhcSession), HscEnvEq,+ IdeState, List (..),+ NormalizedFilePath,+ Position (Position), Range (Range),+ evalGhcEnv, hscEnvWithImportPaths,+ realSrcSpanToRange, runAction,+ toNormalizedUri, uriToFilePath', use,+ use_)+import GHC (DynFlags (importPaths), GenLocated (L),+ HsModule (hsmodName),+ ParsedModule (pm_parsed_source),+ SrcSpan (RealSrcSpan),+ getSessionDynFlags, unLoc)+import Ide.PluginUtils (getProcessID, mkLspCmdId)+import Ide.Types+import Language.LSP.Server+import Language.LSP.Types+import Language.LSP.VFS (virtualFileText)+import System.Directory (canonicalizePath)+import System.FilePath (dropExtension, splitDirectories,+ takeFileName)++-- |Plugin descriptor+descriptor :: PluginId -> PluginDescriptor IdeState+descriptor plId =+ (defaultPluginDescriptor plId)+ { pluginHandlers = mkPluginHandler STextDocumentCodeLens codeLens+ , pluginCommands = [PluginCommand editCommandName editCommandName command]+ }++editCommandName :: IsString p => p+editCommandName = "edit"++asCodeLens :: Text -> Action -> CodeLens+asCodeLens cid Replace{..} =+ CodeLens+ aRange+ (Just $ Command aTitle cid (Just (List [toJSON aUri])))+ Nothing++-- | Generate code lenses+codeLens :: PluginMethodHandler IdeState TextDocumentCodeLens+codeLens state pluginId CodeLensParams{_textDocument=TextDocumentIdentifier uri} = do+ do+ pid <- liftIO $ pack . show <$> getProcessID+ Right . List . maybeToList . (asCodeLens (mkLspCmdId pid pluginId editCommandName) <$>) <$> action state uri++-- | (Quasi) Idempotent command execution: recalculate action to execute on command request+command :: CommandFunction IdeState Uri+command state uri = do+ actMaybe <- action state uri+ case actMaybe of+ Nothing -> pure ()+ Just act -> void $ sendRequest SWorkspaceApplyEdit (ApplyWorkspaceEditParams Nothing (asEdit act)) (\_ -> pure ())+ return (Right Null)++-- | A source code change+data Action = Replace {aUri :: Uri, aRange :: Range, aTitle :: Text, aCode :: Text} deriving (Show)++-- | Convert an Action to the corresponding edit operation+asEdit :: Action -> WorkspaceEdit+asEdit act@Replace{..} =+ WorkspaceEdit (Just $ Map.singleton aUri $ List (asTextEdits act)) Nothing Nothing++asTextEdits :: Action -> [TextEdit]+asTextEdits Replace{..} = [TextEdit aRange aCode]++-- | Required action (that can be converted to either CodeLenses or CodeActions)+action :: IdeState -> Uri -> LspM c (Maybe Action)+action state uri =+ traceAs "action" <$> do+ let Just nfp = uriToNormalizedFilePath $ toNormalizedUri uri+ let Just fp = uriToFilePath' uri++ contents <- getVirtualFile $ toNormalizedUri uri+ let emptyModule = maybe True (T.null . T.strip . virtualFileText) contents++ correctNameMaybe <- liftIO $ traceAs "correctName" <$> pathModuleName state nfp fp+ statedNameMaybe <- liftIO $ traceAs "statedName" <$> codeModuleName state nfp++ let act = Replace uri+ let todo = case (correctNameMaybe, statedNameMaybe) of+ (Just correctName, Just (nameRange, statedName))+ | correctName /= statedName ->+ Just $+ act+ nameRange+ ("Set module name to " <> correctName)+ correctName+ (Just correctName, _)+ | emptyModule ->+ let code = T.unwords ["module", correctName, "where\n"]+ in Just $ act (Range (Position 0 0) (Position 0 0)) code code+ _ -> Nothing+ return todo++-- | The module name, as derived by the position of the module in its source directory+pathModuleName :: IdeState -> NormalizedFilePath -> String -> IO (Maybe Text)+pathModuleName state normFilePath filePath+ | isLower (head $ takeFileName filePath) = return $ Just "Main"+ | otherwise = do+ session :: HscEnvEq <- runAction "ModuleName.ghcSession" state $ use_ GhcSession normFilePath+ srcPaths <- evalGhcEnv (hscEnvWithImportPaths session) $ importPaths <$> getSessionDynFlags+ paths <- mapM canonicalizePath srcPaths+ mdlPath <- canonicalizePath filePath+ let maybePrefix = find (`isPrefixOf` mdlPath) paths++ let maybeMdlName =+ ( \prefix ->+ intercalate "."+ . splitDirectories+ . drop (length prefix + 1)+ $ dropExtension mdlPath+ )+ <$> maybePrefix+ return $ T.pack <$> maybeMdlName++-- | The module name, as stated in the module+codeModuleName :: IdeState -> NormalizedFilePath -> IO (Maybe (Range, Text))+codeModuleName state nfp =+ ((\(L (RealSrcSpan l) m) -> (realSrcSpanToRange l, T.pack . show $ m)) <$>)+ . ((hsmodName . unLoc . pm_parsed_source) =<<)+ <$> runAction "ModuleName.GetParsedModule" state (use GetParsedModule nfp)++-- traceAs :: Show a => String -> a -> a+-- traceAs lbl a = trace (lbl ++ " = " ++ show a) a++traceAs :: b -> a -> a+traceAs _ a = a
@@ -1,80 +1,80 @@-{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE PackageImports #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications #-} - -module Ide.Plugin.Ormolu - ( - descriptor - , provider - ) -where - -import Control.Exception -import qualified Data.Text as T -import Development.IDE hiding (pluginHandlers) -import qualified DynFlags as D -import qualified EnumSet as S -import GHC -import GHC.LanguageExtensions.Type -import GhcPlugins (HscEnv (hsc_dflags)) -import Ide.PluginUtils -import Ide.Types -import Language.LSP.Server -import Language.LSP.Types -import "ormolu" Ormolu -import System.FilePath (takeFileName) -import Text.Regex.TDFA.Text () -import Control.Monad.IO.Class - --- --------------------------------------------------------------------- - -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) - { pluginHandlers = mkFormattingHandlers provider - } - --- --------------------------------------------------------------------- - -provider :: FormattingHandler IdeState -provider ideState typ contents fp _ = withIndefiniteProgress title Cancellable $ liftIO $ do - let - fromDyn :: DynFlags -> IO [DynOption] - fromDyn df = - let - pp = - let p = D.sPgm_F $ D.settings df - in ["-pgmF=" <> p | not (null p)] - pm = map (("-fplugin=" <>) . moduleNameString) $ D.pluginModNames df - ex = map showExtension $ S.toList $ D.extensionFlags df - in - return $ map DynOption $ pp <> pm <> ex - - ghc <- runAction "Ormolu" ideState $ use GhcSession fp - let df = hsc_dflags . hscEnv <$> ghc - fileOpts <- case df of - Nothing -> return [] - Just df -> fromDyn df - - let - fullRegion = RegionIndices Nothing Nothing - rangeRegion s e = RegionIndices (Just $ s + 1) (Just $ e + 1) - mkConf o region = defaultConfig { cfgDynOptions = o, cfgRegion = region } - fmt :: T.Text -> Config RegionIndices -> IO (Either OrmoluException T.Text) - fmt cont conf = - try @OrmoluException (ormolu conf (fromNormalizedFilePath fp) $ T.unpack cont) - - case typ of - FormatText -> ret <$> fmt contents (mkConf fileOpts fullRegion) - FormatRange (Range (Position sl _) (Position el _)) -> - ret <$> fmt contents (mkConf fileOpts (rangeRegion sl el)) - where - title = T.pack $ "Formatting " <> takeFileName (fromNormalizedFilePath fp) - ret :: Either OrmoluException T.Text -> Either ResponseError (List TextEdit) - ret (Left err) = Left - (responseError (T.pack $ "ormoluCmd: " ++ show err) ) - ret (Right new) = Right (makeDiffTextEdit contents new) - -showExtension :: Extension -> String -showExtension Cpp = "-XCPP" -showExtension other = "-X" ++ show other +{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++module Ide.Plugin.Ormolu+ (+ descriptor+ , provider+ )+where++import Control.Exception+import Control.Monad.IO.Class+import qualified Data.Text as T+import Development.IDE hiding (pluginHandlers)+import qualified DynFlags as D+import qualified EnumSet as S+import GHC+import GHC.LanguageExtensions.Type+import GhcPlugins (HscEnv (hsc_dflags))+import Ide.PluginUtils+import Ide.Types+import Language.LSP.Server hiding (defaultConfig)+import Language.LSP.Types+import "ormolu" Ormolu+import System.FilePath (takeFileName)+import Text.Regex.TDFA.Text ()++-- ---------------------------------------------------------------------++descriptor :: PluginId -> PluginDescriptor IdeState+descriptor plId = (defaultPluginDescriptor plId)+ { pluginHandlers = mkFormattingHandlers provider+ }++-- ---------------------------------------------------------------------++provider :: FormattingHandler IdeState+provider ideState typ contents fp _ = withIndefiniteProgress title Cancellable $ liftIO $ do+ let+ fromDyn :: DynFlags -> IO [DynOption]+ fromDyn df =+ let+ pp =+ let p = D.sPgm_F $ D.settings df+ in ["-pgmF=" <> p | not (null p)]+ pm = map (("-fplugin=" <>) . moduleNameString) $ D.pluginModNames df+ ex = map showExtension $ S.toList $ D.extensionFlags df+ in+ return $ map DynOption $ pp <> pm <> ex++ ghc <- runAction "Ormolu" ideState $ use GhcSession fp+ let df = hsc_dflags . hscEnv <$> ghc+ fileOpts <- case df of+ Nothing -> return []+ Just df -> fromDyn df++ let+ fullRegion = RegionIndices Nothing Nothing+ rangeRegion s e = RegionIndices (Just $ s + 1) (Just $ e + 1)+ mkConf o region = defaultConfig { cfgDynOptions = o, cfgRegion = region }+ fmt :: T.Text -> Config RegionIndices -> IO (Either OrmoluException T.Text)+ fmt cont conf =+ try @OrmoluException (ormolu conf (fromNormalizedFilePath fp) $ T.unpack cont)++ case typ of+ FormatText -> ret <$> fmt contents (mkConf fileOpts fullRegion)+ FormatRange (Range (Position sl _) (Position el _)) ->+ ret <$> fmt contents (mkConf fileOpts (rangeRegion sl el))+ where+ title = T.pack $ "Formatting " <> takeFileName (fromNormalizedFilePath fp)+ ret :: Either OrmoluException T.Text -> Either ResponseError (List TextEdit)+ ret (Left err) = Left+ (responseError (T.pack $ "ormoluCmd: " ++ show err) )+ ret (Right new) = Right (makeDiffTextEdit contents new)++showExtension :: Extension -> String+showExtension Cpp = "-XCPP"+showExtension other = "-X" ++ show other
@@ -1,189 +1,191 @@-{-# LANGUAGE DuplicateRecordFields #-} -{-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ViewPatterns #-} - --- | Provides code actions to add missing pragmas (whenever GHC suggests to) -module Ide.Plugin.Pragmas (descriptor) where - -import Control.Applicative ((<|>)) -import Control.Lens hiding (List) -import Control.Monad (join) -import Control.Monad.IO.Class -import qualified Data.HashMap.Strict as H -import Data.List.Extra (nubOrdOn) -import Data.Maybe (catMaybes, listToMaybe) -import qualified Data.Text as T -import Development.IDE as D -import Development.IDE.GHC.Compat -import Ide.Types -import qualified Language.LSP.Server as LSP -import Language.LSP.Types -import qualified Language.LSP.Types as J -import qualified Language.LSP.Types.Lens as J -import qualified Language.LSP.VFS as VFS -import qualified Text.Fuzzy as Fuzzy - --- --------------------------------------------------------------------- - -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) - { pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionProvider - <> mkPluginHandler STextDocumentCompletion completion - } - --- --------------------------------------------------------------------- - --- | Title and pragma -type PragmaEdit = (T.Text, Pragma) - -data Pragma = LangExt T.Text | OptGHC T.Text - deriving (Show, Eq, Ord) - -codeActionProvider :: PluginMethodHandler IdeState TextDocumentCodeAction -codeActionProvider state _plId (CodeActionParams _ _ docId _ (J.CodeActionContext (J.List diags) _monly)) = do - let mFile = docId ^. J.uri & uriToFilePath <&> toNormalizedFilePath' - uri = docId ^. J.uri - pm <- liftIO $ fmap join $ runAction "Pragmas.GetParsedModule" state $ getParsedModule `traverse` mFile - let dflags = ms_hspp_opts . pm_mod_summary <$> pm - insertRange = maybe (Range (Position 0 0) (Position 0 0)) endOfModuleHeader pm - pedits = nubOrdOn snd . concat $ suggest dflags <$> diags - return $ Right $ List $ pragmaEditToAction uri insertRange <$> pedits - --- | Add a Pragma to the given URI at the top of the file. --- It is assumed that the pragma name is a valid pragma, --- thus, not validated. -pragmaEditToAction :: Uri -> Range -> PragmaEdit -> (Command |? CodeAction) -pragmaEditToAction uri range (title, p) = - InR $ J.CodeAction title (Just J.CodeActionQuickFix) (Just (J.List [])) Nothing Nothing (Just edit) Nothing - where - render (OptGHC x) = "{-# OPTIONS_GHC -Wno-" <> x <> " #-}\n" - render (LangExt x) = "{-# LANGUAGE " <> x <> " #-}\n" - textEdits = J.List [J.TextEdit range $ render p] - edit = - J.WorkspaceEdit - (Just $ H.singleton uri textEdits) - Nothing - -suggest :: Maybe DynFlags -> Diagnostic -> [PragmaEdit] -suggest dflags diag = - suggestAddPragma dflags diag - ++ suggestDisableWarning diag - --- --------------------------------------------------------------------- - -suggestDisableWarning :: Diagnostic -> [PragmaEdit] -suggestDisableWarning Diagnostic {_code} - | Just (InR (T.stripPrefix "-W" -> Just w)) <- _code = - pure ("Disable \"" <> w <> "\" warnings", OptGHC w) - | otherwise = [] - --- --------------------------------------------------------------------- - --- | Offer to add a missing Language Pragma to the top of a file. --- Pragmas are defined by a curated list of known pragmas, see 'possiblePragmas'. -suggestAddPragma :: Maybe DynFlags -> Diagnostic -> [PragmaEdit] -suggestAddPragma mDynflags Diagnostic {_message} = genPragma _message - where - genPragma target = - [("Add \"" <> r <> "\"", LangExt r) | r <- findPragma target, r `notElem` disabled] - disabled - | Just dynFlags <- mDynflags = - -- GHC does not export 'OnOff', so we have to view it as string - catMaybes $ T.stripPrefix "Off " . T.pack . prettyPrint <$> extensions dynFlags - | otherwise = - -- When the module failed to parse, we don't have access to its - -- dynFlags. In that case, simply don't disable any pragmas. - [] - --- | Find all Pragmas are an infix of the search term. -findPragma :: T.Text -> [T.Text] -findPragma str = concatMap check possiblePragmas - where - check p = [p | T.isInfixOf p str] - - -- We exclude the Strict extension as it causes many false positives, see - -- the discussion at https://github.com/haskell/ghcide/pull/638 - -- - -- We don't include the No- variants, as GHC never suggests disabling an - -- extension in an error message. - possiblePragmas :: [T.Text] - possiblePragmas = - [ name - | FlagSpec{flagSpecName = T.pack -> name} <- xFlags - , "Strict" /= name - ] - --- | All language pragmas, including the No- variants -allPragmas :: [T.Text] -allPragmas = - concat - [ [name, "No" <> name] - | FlagSpec{flagSpecName = T.pack -> name} <- xFlags - ] - <> - -- These pragmas are not part of xFlags as they are not reversable - -- by prepending "No". - [ -- Safe Haskell - "Unsafe" - , "Trustworthy" - , "Safe" - - -- Language Version Extensions - , "Haskell98" - , "Haskell2010" - -- Maybe, GHC 2021 after its release? - ] - --- --------------------------------------------------------------------- - -completion :: PluginMethodHandler IdeState TextDocumentCompletion -completion _ide _ complParams = do - let (TextDocumentIdentifier uri) = complParams ^. J.textDocument - position = complParams ^. J.position - contents <- LSP.getVirtualFile $ toNormalizedUri uri - fmap (Right . InL) $ case (contents, uriToFilePath' uri) of - (Just cnts, Just _path) -> - result <$> VFS.getCompletionPrefix position cnts - where - result (Just pfix) - | "{-# LANGUAGE" `T.isPrefixOf` VFS.fullLine pfix - = List $ map buildCompletion - (Fuzzy.simpleFilter (VFS.prefixText pfix) allPragmas) - | otherwise - = List [] - result Nothing = List [] - buildCompletion p = - CompletionItem - { _label = p, - _kind = Just CiKeyword, - _tags = Nothing, - _detail = Nothing, - _documentation = Nothing, - _deprecated = Nothing, - _preselect = Nothing, - _sortText = Nothing, - _filterText = Nothing, - _insertText = Nothing, - _insertTextFormat = Nothing, - _textEdit = Nothing, - _additionalTextEdits = Nothing, - _commitCharacters = Nothing, - _command = Nothing, - _xdata = Nothing - } - _ -> return $ List [] - --- --------------------------------------------------------------------- - --- | Find the first non-blank line before the first of (module name / imports / declarations). --- Useful for inserting pragmas. -endOfModuleHeader :: ParsedModule -> Range -endOfModuleHeader pm = - let mod = unLoc $ pm_parsed_source pm - modNameLoc = getLoc <$> hsmodName mod - firstImportLoc = getLoc <$> listToMaybe (hsmodImports mod) - firstDeclLoc = getLoc <$> listToMaybe (hsmodDecls mod) - line = maybe 0 (_line . _start) (modNameLoc <|> firstImportLoc <|> firstDeclLoc >>= srcSpanToRange) - loc = Position line 0 - in Range loc loc +{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-}++-- | Provides code actions to add missing pragmas (whenever GHC suggests to)+module Ide.Plugin.Pragmas (descriptor) where++import Control.Applicative ((<|>))+import Control.Lens hiding (List)+import Control.Monad (join)+import Control.Monad.IO.Class+import qualified Data.HashMap.Strict as H+import Data.List.Extra (nubOrdOn)+import Data.Maybe (catMaybes, listToMaybe)+import qualified Data.Text as T+import Development.IDE as D+import Development.IDE.GHC.Compat+import Ide.Types+import qualified Language.LSP.Server as LSP+import Language.LSP.Types+import qualified Language.LSP.Types as J+import qualified Language.LSP.Types.Lens as J+import qualified Language.LSP.VFS as VFS+import qualified Text.Fuzzy as Fuzzy++-- ---------------------------------------------------------------------++descriptor :: PluginId -> PluginDescriptor IdeState+descriptor plId = (defaultPluginDescriptor plId)+ { pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionProvider+ <> mkPluginHandler STextDocumentCompletion completion+ }++-- ---------------------------------------------------------------------++-- | Title and pragma+type PragmaEdit = (T.Text, Pragma)++data Pragma = LangExt T.Text | OptGHC T.Text+ deriving (Show, Eq, Ord)++codeActionProvider :: PluginMethodHandler IdeState TextDocumentCodeAction+codeActionProvider state _plId (CodeActionParams _ _ docId _ (J.CodeActionContext (J.List diags) _monly)) = do+ let mFile = docId ^. J.uri & uriToFilePath <&> toNormalizedFilePath'+ uri = docId ^. J.uri+ pm <- liftIO $ fmap join $ runAction "Pragmas.GetParsedModule" state $ getParsedModule `traverse` mFile+ let dflags = ms_hspp_opts . pm_mod_summary <$> pm+ insertRange = maybe (Range (Position 0 0) (Position 0 0)) endOfModuleHeader pm+ pedits = nubOrdOn snd . concat $ suggest dflags <$> diags+ return $ Right $ List $ pragmaEditToAction uri insertRange <$> pedits++-- | Add a Pragma to the given URI at the top of the file.+-- It is assumed that the pragma name is a valid pragma,+-- thus, not validated.+pragmaEditToAction :: Uri -> Range -> PragmaEdit -> (Command |? CodeAction)+pragmaEditToAction uri range (title, p) =+ InR $ J.CodeAction title (Just J.CodeActionQuickFix) (Just (J.List [])) Nothing Nothing (Just edit) Nothing Nothing+ where+ render (OptGHC x) = "{-# OPTIONS_GHC -Wno-" <> x <> " #-}\n"+ render (LangExt x) = "{-# LANGUAGE " <> x <> " #-}\n"+ textEdits = J.List [J.TextEdit range $ render p]+ edit =+ J.WorkspaceEdit+ (Just $ H.singleton uri textEdits)+ Nothing+ Nothing++suggest :: Maybe DynFlags -> Diagnostic -> [PragmaEdit]+suggest dflags diag =+ suggestAddPragma dflags diag+ ++ suggestDisableWarning diag++-- ---------------------------------------------------------------------++suggestDisableWarning :: Diagnostic -> [PragmaEdit]+suggestDisableWarning Diagnostic {_code}+ | Just (InR (T.stripPrefix "-W" -> Just w)) <- _code =+ pure ("Disable \"" <> w <> "\" warnings", OptGHC w)+ | otherwise = []++-- ---------------------------------------------------------------------++-- | Offer to add a missing Language Pragma to the top of a file.+-- Pragmas are defined by a curated list of known pragmas, see 'possiblePragmas'.+suggestAddPragma :: Maybe DynFlags -> Diagnostic -> [PragmaEdit]+suggestAddPragma mDynflags Diagnostic {_message} = genPragma _message+ where+ genPragma target =+ [("Add \"" <> r <> "\"", LangExt r) | r <- findPragma target, r `notElem` disabled]+ disabled+ | Just dynFlags <- mDynflags =+ -- GHC does not export 'OnOff', so we have to view it as string+ catMaybes $ T.stripPrefix "Off " . T.pack . prettyPrint <$> extensions dynFlags+ | otherwise =+ -- When the module failed to parse, we don't have access to its+ -- dynFlags. In that case, simply don't disable any pragmas.+ []++-- | Find all Pragmas are an infix of the search term.+findPragma :: T.Text -> [T.Text]+findPragma str = concatMap check possiblePragmas+ where+ check p = [p | T.isInfixOf p str]++ -- We exclude the Strict extension as it causes many false positives, see+ -- the discussion at https://github.com/haskell/ghcide/pull/638+ --+ -- We don't include the No- variants, as GHC never suggests disabling an+ -- extension in an error message.+ possiblePragmas :: [T.Text]+ possiblePragmas =+ [ name+ | FlagSpec{flagSpecName = T.pack -> name} <- xFlags+ , "Strict" /= name+ ]++-- | All language pragmas, including the No- variants+allPragmas :: [T.Text]+allPragmas =+ concat+ [ [name, "No" <> name]+ | FlagSpec{flagSpecName = T.pack -> name} <- xFlags+ ]+ <>+ -- These pragmas are not part of xFlags as they are not reversable+ -- by prepending "No".+ [ -- Safe Haskell+ "Unsafe"+ , "Trustworthy"+ , "Safe"++ -- Language Version Extensions+ , "Haskell98"+ , "Haskell2010"+ -- Maybe, GHC 2021 after its release?+ ]++-- ---------------------------------------------------------------------++completion :: PluginMethodHandler IdeState TextDocumentCompletion+completion _ide _ complParams = do+ let (TextDocumentIdentifier uri) = complParams ^. J.textDocument+ position = complParams ^. J.position+ contents <- LSP.getVirtualFile $ toNormalizedUri uri+ fmap (Right . InL) $ case (contents, uriToFilePath' uri) of+ (Just cnts, Just _path) ->+ result <$> VFS.getCompletionPrefix position cnts+ where+ result (Just pfix)+ | "{-# LANGUAGE" `T.isPrefixOf` VFS.fullLine pfix+ = List $ map buildCompletion+ (Fuzzy.simpleFilter (VFS.prefixText pfix) allPragmas)+ | otherwise+ = List []+ result Nothing = List []+ buildCompletion p =+ CompletionItem+ { _label = p,+ _kind = Just CiKeyword,+ _tags = Nothing,+ _detail = Nothing,+ _documentation = Nothing,+ _deprecated = Nothing,+ _preselect = Nothing,+ _sortText = Nothing,+ _filterText = Nothing,+ _insertText = Nothing,+ _insertTextFormat = Nothing,+ _insertTextMode = Nothing,+ _textEdit = Nothing,+ _additionalTextEdits = Nothing,+ _commitCharacters = Nothing,+ _command = Nothing,+ _xdata = Nothing+ }+ _ -> return $ List []++-- ---------------------------------------------------------------------++-- | Find the first non-blank line before the first of (module name / imports / declarations).+-- Useful for inserting pragmas.+endOfModuleHeader :: ParsedModule -> Range+endOfModuleHeader pm =+ let mod = unLoc $ pm_parsed_source pm+ modNameLoc = getLoc <$> hsmodName mod+ firstImportLoc = getLoc <$> listToMaybe (hsmodImports mod)+ firstDeclLoc = getLoc <$> listToMaybe (hsmodDecls mod)+ line = maybe 0 (_line . _start) (modNameLoc <|> firstImportLoc <|> firstDeclLoc >>= srcSpanToRange)+ loc = Position line 0+ in Range loc loc
@@ -1,82 +0,0 @@-{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ViewPatterns #-} -module Ide.Plugin.StylishHaskell - ( - descriptor - , provider - ) -where - -import Control.Monad.IO.Class -import Data.Text (Text) -import qualified Data.Text as T -import Development.IDE hiding (pluginHandlers) -import Development.IDE.GHC.Compat (ModSummary (ms_hspp_opts)) -import qualified DynFlags as D -import qualified EnumSet as ES -import GHC.LanguageExtensions.Type -import Ide.PluginUtils -import Ide.Types -import Language.Haskell.Stylish -import Language.LSP.Types as J - -import System.Directory -import System.FilePath - -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) - { pluginHandlers = mkFormattingHandlers provider - } - --- | Formatter provider of stylish-haskell. --- Formats the given source in either a given Range or the whole Document. --- If the provider fails an error is returned that can be displayed to the user. -provider :: FormattingHandler IdeState -provider ide typ contents fp _opts = do - (ms_hspp_opts -> dyn, _) <- liftIO $ runAction "stylish-haskell" ide $ use_ GetModSummary fp - let file = fromNormalizedFilePath fp - config <- liftIO $ loadConfigFrom file - mergedConfig <- liftIO $ getMergedConfig dyn config - let (range, selectedContents) = case typ of - FormatText -> (fullRange contents, contents) - FormatRange r -> (normalize r, extractRange r contents) - result = runStylishHaskell file mergedConfig selectedContents - case result of - Left err -> return $ Left $ responseError $ T.pack $ "stylishHaskellCmd: " ++ err - Right new -> return $ Right $ J.List [TextEdit range new] - where - getMergedConfig dyn config - | null (configLanguageExtensions config) - = do - logInfo (ideLogger ide) "stylish-haskell uses the language extensions from DynFlags" - pure - $ config - { configLanguageExtensions = getExtensions dyn } - | otherwise - = pure config - - getExtensions = map showExtension . ES.toList . D.extensionFlags - - showExtension Cpp = "CPP" - showExtension other = show other - --- | Recursively search in every directory of the given filepath for .stylish-haskell.yaml. --- If no such file has been found, return default config. -loadConfigFrom :: FilePath -> IO Config -loadConfigFrom file = do - currDir <- getCurrentDirectory - setCurrentDirectory (takeDirectory file) - config <- loadConfig (makeVerbose False) Nothing - setCurrentDirectory currDir - pure config - --- | Run stylish-haskell on the given text with the given configuration. -runStylishHaskell :: FilePath -- ^ Location of the file being formatted. Used for error message - -> Config -- ^ Configuration for stylish-haskell - -> Text -- ^ Text to format - -> Either String Text -- ^ Either formatted Text or an error message -runStylishHaskell file config = fmap fromLines . fmt . toLines - where - fromLines = T.pack . unlines - fmt = runSteps (configLanguageExtensions config) (Just file) (configSteps config) - toLines = lines . T.unpack
@@ -1,162 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveFunctor #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE UndecidableInstances #-} -{-# OPTIONS_GHC -Wwarn #-} - -module Ide.Plugin.Eval.Types - ( locate, - locate0, - Test (..), - isProperty, - Format (..), - Language (..), - Section (..), - Sections (..), - hasTests, - hasPropertyTest, - splitSections, - Loc, - Located (..), - Comments (..), - RawBlockComment (..), - RawLineComment (..), - unLoc, - Txt, - EvalParams(..), - ) -where - -import Control.DeepSeq (NFData (rnf), deepseq) -import Data.Aeson (FromJSON, ToJSON) -import Data.List (partition) -import Data.List.NonEmpty (NonEmpty) -import Data.Map.Strict (Map) -import Data.String (IsString (..)) -import Development.IDE (Range) -import GHC.Generics (Generic) -import qualified Text.Megaparsec as P -import Language.LSP.Types (TextDocumentIdentifier) - --- | A thing with a location attached. -data Located l a = Located {location :: l, located :: a} - deriving (Eq, Show, Ord, Functor, Generic, FromJSON, ToJSON) - --- | Discard location information. -unLoc :: Located l a -> a -unLoc (Located _ a) = a - -instance (NFData l, NFData a) => NFData (Located l a) where - rnf (Located loc a) = loc `deepseq` a `deepseq` () - -type Loc = Located Line - -type Line = Int - -locate :: Loc [a] -> [Loc a] -locate (Located l tst) = zipWith Located [l ..] tst - -locate0 :: [a] -> [Loc a] -locate0 = locate . Located 0 - -type Txt = String - -data Sections = Sections - { nonSetupSections :: [Section] - , setupSections :: [Section] - } - deriving (Show, Eq, Generic) - -data Section = Section - { sectionName :: Txt - , sectionTests :: [Test] - , sectionLanguage :: Language - , sectionFormat :: Format - } - deriving (Eq, Show, Generic, FromJSON, ToJSON, NFData) - -hasTests :: Section -> Bool -hasTests = not . null . sectionTests - -hasPropertyTest :: Section -> Bool -hasPropertyTest = any isProperty . sectionTests - --- |Split setup and normal sections -splitSections :: [Section] -> ([Section], [Section]) -splitSections = partition ((== "setup") . sectionName) - -data Test - = Example {testLines :: NonEmpty Txt, testOutput :: [Txt], testRange :: Range} - | Property {testline :: Txt, testOutput :: [Txt], testRange :: Range} - deriving (Eq, Show, Generic, FromJSON, ToJSON, NFData) - -data Comments = Comments - { lineComments :: Map Range RawLineComment - , blockComments :: Map Range RawBlockComment - } - deriving (Show, Eq, Ord, Generic) - -newtype RawBlockComment = RawBlockComment {getRawBlockComment :: String} - deriving (Show, Eq, Ord) - deriving newtype - ( IsString - , P.Stream - , P.TraversableStream - , P.VisualStream - , Semigroup - , Monoid - ) - -newtype RawLineComment = RawLineComment {getRawLineComment :: String} - deriving (Show, Eq, Ord) - deriving newtype - ( IsString - , P.Stream - , P.TraversableStream - , P.VisualStream - , Semigroup - , Monoid - ) - -instance Semigroup Comments where - Comments ls bs <> Comments ls' bs' = Comments (ls <> ls') (bs <> bs') - -instance Monoid Comments where - mempty = Comments mempty mempty - -isProperty :: Test -> Bool -isProperty Property {} = True -isProperty _ = False - -data Format - = SingleLine - | -- | @Range@ is that of surrounding entire block comment, not section. - -- Used for detecting no-newline test commands. - MultiLine Range - deriving (Eq, Show, Ord, Generic, FromJSON, ToJSON, NFData) - -data Language = Plain | Haddock deriving (Eq, Show, Generic, Ord, FromJSON, ToJSON, NFData) - -data ExpectedLine = ExpectedLine [LineChunk] | WildCardLine - deriving (Eq, Show, Generic, FromJSON, ToJSON, NFData) - -instance IsString ExpectedLine where - fromString = ExpectedLine . return . LineChunk - -data LineChunk = LineChunk String | WildCardChunk - deriving (Eq, Show, Generic, FromJSON, ToJSON, NFData) - -instance IsString LineChunk where - fromString = LineChunk - -type EvalId = Int - --- | Specify the test section to execute -data EvalParams = EvalParams - { sections :: [Section] - , module_ :: !TextDocumentIdentifier - , evalId :: !EvalId -- ^ unique group id; for test uses - } - deriving (Eq, Show, Generic, FromJSON, ToJSON)
@@ -1,229 +0,0 @@-{-# LANGUAGE ViewPatterns #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE DuplicateRecordFields #-} - -module Eval ( - tests, -) where - -import Control.Applicative.Combinators ( - skipManyTill - ) -import Control.Monad (when) -import Control.Monad.IO.Class (MonadIO (liftIO)) -import qualified Data.Text as T -import qualified Data.Text.IO as T -import Language.LSP.Test -import Language.LSP.Types -import Language.LSP.Types.Lens (command, title, range) -import Control.Lens (view, _Just, preview) -import System.Directory (doesFileExist) -import System.FilePath ( - (<.>), - (</>), - ) -import Test.Hls.Util (hlsCommand, GhcVersion (GHC84, GHC86), knownBrokenForGhcVersions, knownBrokenInEnv, EnvSpec (HostOS, GhcVer), OS (Windows)) -import Test.Tasty ( - TestTree, - testGroup, - ) -import Test.Tasty.ExpectedFailure ( - expectFailBecause, - ) -import Test.Tasty.HUnit ( - testCase, - (@?=), - ) -import Data.List.Extra (nubOrdOn) -import Ide.Plugin.Eval.Types (EvalParams(..)) -import Data.Aeson (fromJSON) -import Data.Aeson.Types (Result(Success)) - -tests :: TestTree -tests = - testGroup - "eval" - [ testCase "Produces Evaluate code lenses" $ - runSession hlsCommand fullCaps evalPath $ do - doc <- openDoc "T1.hs" "haskell" - lenses <- getEvalCodeLenses doc - liftIO $ map (preview $ command . _Just . title) lenses @?= [Just "Evaluate..."] - , testCase "Produces Refresh code lenses" $ - runSession hlsCommand fullCaps evalPath $ do - doc <- openDoc "T2.hs" "haskell" - lenses <- getEvalCodeLenses doc - liftIO $ map (preview $ command . _Just . title) lenses @?= [Just "Refresh..."] - , testCase "Code lenses have ranges" $ - runSession hlsCommand fullCaps evalPath $ do - doc <- openDoc "T1.hs" "haskell" - lenses <- getEvalCodeLenses doc - liftIO $ map (view range) lenses @?= [Range (Position 4 0) (Position 5 0)] - , testCase "Multi-line expressions have a multi-line range" $ do - runSession hlsCommand fullCaps evalPath $ do - doc <- openDoc "T3.hs" "haskell" - lenses <- getEvalCodeLenses doc - liftIO $ map (view range) lenses @?= [Range (Position 3 0) (Position 5 0)] - , testCase "Executed expressions range covers only the expression" $ do - runSession hlsCommand fullCaps evalPath $ do - doc <- openDoc "T2.hs" "haskell" - lenses <- getEvalCodeLenses doc - liftIO $ map (view range) lenses @?= [Range (Position 4 0) (Position 5 0)] - , testCase "Evaluation of expressions" $ goldenTest "T1.hs" - , testCase "Reevaluation of expressions" $ goldenTest "T2.hs" - , testCase "Evaluation of expressions w/ imports" $ goldenTest "T3.hs" - , testCase "Evaluation of expressions w/ lets" $ goldenTest "T4.hs" - , testCase "Refresh an evaluation" $ goldenTest "T5.hs" - , testCase "Refresh an evaluation w/ lets" $ goldenTest "T6.hs" - , testCase "Refresh a multiline evaluation" $ goldenTest "T7.hs" - , testCase "Semantic and Lexical errors are reported" $ goldenTest "T8.hs" - , testCase "Applies file LANGUAGE extensions" $ goldenTest "T9.hs" - , testCase "Evaluate a type with :kind!" $ goldenTest "T10.hs" - , testCase "Reports an error for an incorrect type with :kind!" $ - goldenTest "T11.hs" - , testCase "Shows a kind with :kind" $ goldenTest "T12.hs" - , testCase "Reports an error for an incorrect type with :kind" $ - goldenTest "T13.hs" - , testCase "Returns a fully-instantiated type for :type" $ - goldenTest "T14.hs" - , testCase "Returns an uninstantiated type for :type +v, admitting multiple whitespaces around arguments" $ - goldenTest "T15.hs" - , testCase "Returns defaulted type for :type +d, admitting multiple whitespaces around arguments" $ - goldenTest "T16.hs" - , testCase ":type reports an error when given with unknown +x option" $ - goldenTest "T17.hs" - , testCase "Reports an error when given with unknown command" $ - goldenTest "T18.hs" - , testCase "Returns defaulted type for :type +d reflecting the default declaration specified in the >>> prompt" $ - goldenTest "T19.hs" - , expectFailBecause "known issue - see a note in P.R. #361" $ - testCase ":type +d reflects the `default' declaration of the module" $ - goldenTest "T20.hs" - , testCase ":type handles a multilined result properly" $ - goldenTest "T21.hs" - , testCase ":t behaves exactly the same as :type" $ - goldenTest "T22.hs" - , testCase ":type does \"dovetails\" for short identifiers" $ - goldenTest "T23.hs" - , testCase ":kind! treats a multilined result properly" $ - goldenTest "T24.hs" - , testCase ":kind treats a multilined result properly" $ - goldenTest "T25.hs" - , testCase "local imports" $ - goldenTest "T26.hs" - , testCase "Preserves one empty comment line after prompt" $ - goldenTest "T27.hs" - , testCase - "Multi line comments" - $ goldenTest "TMulti.hs" - , testCase - "Multi line comments, with the last test line ends without newline" - $ goldenTest "TEndingMulti.hs" - , testCase - "Evaluate expressions in Plain comments in both single line and multi line format" - $ goldenTest "TPlainComment.hs" - , testCase - "Evaluate expressions in Haddock comments in both single line and multi line format" - $ goldenTest "THaddock.hs" - , testCase "Compare results (for Haddock tests only)" $ - goldenTest "TCompare.hs" - , testCase "Local Modules imports are accessible in a test" $ - goldenTest "TLocalImport.hs" - , -- , testCase "Local Modules can be imported in a test" $ goldenTest "TLocalImportInTest.hs" - expectFailBecause "Unexplained but minor issue" $ - testCase "Setting language option TupleSections" $ - goldenTest "TLanguageOptionsTupleSections.hs" - , testCase ":set accepts ghci flags" $ - goldenTest "TFlags.hs" - , testCase "IO expressions are supported, stdout/stderr output is ignored" $ - goldenTest "TIO.hs" - , testCase "Property checking" $ goldenTest "TProperty.hs" - , testCase - "Prelude has no special treatment, it is imported as stated in the module" - $ goldenTest "TPrelude.hs" - , testCase - "Don't panic on {-# UNPACK #-} pragma" - $ goldenTest "TUNPACK.hs" - , testCase - "Can handle eval inside nested comment properly" - $ goldenTest "TNested.hs" - , testCase "Test on last line insert results correctly" $ do - runSession hlsCommand fullCaps evalPath $ - liftIO $ do - let mdl = "TLastLine.hs" - -- Write the test file, to make sure that it has no final line return - writeFile (evalPath </> mdl) "module TLastLine where\n\n-- >>> take 3 [1..]" - goldenTest mdl - , testGroup "with preprocessors" - [ knownBrokenInEnv [HostOS Windows, GhcVer GHC84, GhcVer GHC86] - "CPP eval on Windows and/or GHC <= 8.6 fails for some reasons" $ - testCase "CPP support" $ goldenTest "TCPP.hs" - , knownBrokenForGhcVersions [GHC84, GHC86] - "Preprocessor known to fail on GHC <= 8.6" - $ testCase "Literate Haskell Bird Style" $ goldenTest "TLHS.lhs" - -- , testCase "Literate Haskell LaTeX Style" $ goldenTest "TLHSLateX.lhs" - ] - ] - -goldenTest :: FilePath -> IO () -goldenTest = goldenTestBy isEvalTest - -{- |Execute all CodeLens accepted by 'filter' - Compare results with the contents of corresponding '.expected' file (and creates it, if missing) --} -goldenTestBy :: (CodeLens -> Bool) -> FilePath -> IO () -goldenTestBy fltr input = runSession hlsCommand fullCaps evalPath $ do - doc <- openDoc input "haskell" - - -- Execute lenses backwards, to avoid affecting their position in the source file - codeLenses <- reverse <$> getCodeLensesBy fltr doc - -- liftIO $ print codeLenses - - -- Execute sequentially, nubbing elements to avoid - -- evaluating the same section with multiple tests - -- more than twice - mapM_ executeCmd - $ nubOrdOn actSectionId [c | CodeLens{_command = Just c} <- codeLenses] - - edited <- replaceUnicodeQuotes <$> documentContents doc - -- liftIO $ T.putStrLn edited - - let expectedFile = evalPath </> input <.> "expected" - - liftIO $ do - -- Write expected file if missing - missingExpected <- not <$> doesFileExist expectedFile - when missingExpected $ T.writeFile expectedFile edited - expected <- T.readFile expectedFile - edited @?= expected - -actSectionId :: Command -> Int -actSectionId Command{_arguments = Just (List [fromJSON -> Success EvalParams{..}])} = evalId -actSectionId _ = error "Invalid CodeLens" - -getEvalCodeLenses :: TextDocumentIdentifier -> Session [CodeLens] -getEvalCodeLenses = getCodeLensesBy isEvalTest - -getCodeLensesBy :: (CodeLens -> Bool) -> TextDocumentIdentifier -> Session [CodeLens] -getCodeLensesBy f doc = filter f <$> getCodeLenses doc - --- Execute command and wait for result -executeCmd :: Command -> Session () -executeCmd cmd = do - executeCommand cmd - _resp <- skipManyTill anyMessage (message SWorkspaceApplyEdit) - -- liftIO $ print _resp - return () - --- Execute only Eval tests to avoid interference from other plugins (e.g ghcide:typesignature.add) -isEvalTest :: CodeLens -> Bool -isEvalTest (CodeLens _ (Just (Command _ cmd _)) _) - | ":eval:" `T.isInfixOf` cmd = True -isEvalTest _ = False - -replaceUnicodeQuotes :: T.Text -> T.Text -replaceUnicodeQuotes = T.replace "‘" "'" . T.replace "’" "'" - -evalPath :: FilePath -evalPath = "plugins/hls-eval-plugin/test/testdata"
@@ -1,54 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DerivingStrategies #-} - -module Ide.Plugin.Splice.Types where - -import Data.Aeson (FromJSON, ToJSON) -import Development.IDE (Uri) -import GHC.Generics (Generic) -import Development.IDE.GHC.Compat (RealSrcSpan) -import qualified Data.Text as T -import Ide.Types ( CommandId ) - --- | Parameter for the addMethods PluginCommand. -data ExpandSpliceParams = ExpandSpliceParams - { uri :: Uri - , spliceSpan :: RealSrcSpan - , spliceContext :: SpliceContext - } - deriving (Show, Eq, Generic) - deriving anyclass (ToJSON, FromJSON) - --- FIXME: HsDecl needs different treatment of splicing. -data SpliceContext = Expr | HsDecl | Pat | HsType - deriving (Read, Show, Eq, Ord, Generic) - deriving anyclass (ToJSON, FromJSON) - -data ExpandStyle = Inplace | Commented - deriving (Read, Show, Eq, Ord, Generic) - -expandStyles :: [(ExpandStyle, (T.Text, CommandId))] -expandStyles = - [ (Inplace, (inplaceCmdName, expandInplaceId)) - -- , (Commented, commentedCmdName, expandCommentedId) - ] - -toExpandCmdTitle :: ExpandStyle -> T.Text -toExpandCmdTitle Inplace = inplaceCmdName -toExpandCmdTitle Commented = commentedCmdName - -toCommandId :: ExpandStyle -> CommandId -toCommandId Inplace = expandInplaceId -toCommandId Commented = expandCommentedId - -expandInplaceId, expandCommentedId :: CommandId -expandInplaceId = "expandTHSpliceInplace" -expandCommentedId = "expandTHSpliceCommented" - -inplaceCmdName :: T.Text -inplaceCmdName = "expand TemplateHaskell Splice (in-place)" - -commentedCmdName :: T.Text -commentedCmdName = "expand TemplateHaskell Splice (comented-out)"
@@ -1,130 +1,141 @@--- Copyright (c) 2019 The DAML Authors. All rights reserved. --- SPDX-License-Identifier: Apache-2.0 -{-# LANGUAGE CPP #-} -- To get precise GHC version -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TupleSections #-} -{-# LANGUAGE ViewPatterns #-} -{-# OPTIONS_GHC -Wno-dodgy-imports #-} -- GHC no longer exports def in GHC 8.6 and above - -module Ide.Arguments - ( Arguments(..) - , LspArguments(..) - , PrintVersion(..) - , getArguments - , haskellLanguageServerVersion - , haskellLanguageServerNumericVersion - ) where - -import Data.Version -import Development.GitRev -import Options.Applicative -import Paths_haskell_language_server -import System.Environment -import HieDb.Run - --- --------------------------------------------------------------------- - -data Arguments - = VersionMode PrintVersion - | ProbeToolsMode - | DbCmd Options Command - | LspMode LspArguments - -data LspArguments = LspArguments - {argLSP :: Bool - ,argsCwd :: Maybe FilePath - ,argFiles :: [FilePath] - ,argsShakeProfiling :: Maybe FilePath - ,argsTesting :: Bool - ,argsExamplePlugin :: Bool - -- These next two are for compatibility with existing hie clients, allowing - -- them to just change the name of the exe and still work. - , argsDebugOn :: Bool - , argsLogFile :: Maybe String - , argsThreads :: Int - , argsProjectGhcVersion :: Bool - } deriving Show - -data PrintVersion - = PrintVersion - | PrintNumericVersion - deriving (Show, Eq, Ord) - -getArguments :: String -> IO Arguments -getArguments exeName = execParser opts - where - hieInfo = fullDesc <> progDesc "Query .hie files" - opts = info (( - VersionMode <$> printVersionParser exeName - <|> probeToolsParser exeName - <|> hsubparser (command "hiedb" (info (DbCmd <$> optParser "" True <*> cmdParser <**> helper) hieInfo)) - <|> LspMode <$> arguments) - <**> helper) - ( fullDesc - <> progDesc "Used as a test bed to check your IDE Client will work" - <> header (exeName ++ " - GHC Haskell LSP server")) - -printVersionParser :: String -> Parser PrintVersion -printVersionParser exeName = - flag' PrintVersion - (long "version" <> help ("Show " ++ exeName ++ " and GHC versions")) - <|> - flag' PrintNumericVersion - (long "numeric-version" <> help ("Show numeric version of " ++ exeName)) - -probeToolsParser :: String -> Parser Arguments -probeToolsParser exeName = - flag' ProbeToolsMode - (long "probe-tools" <> help ("Show " ++ exeName ++ " version and other tools of interest")) - -arguments :: Parser LspArguments -arguments = LspArguments - <$> switch (long "lsp" <> help "Start talking to an LSP server") - <*> optional (strOption $ long "cwd" <> metavar "DIR" - <> help "Change to this directory") - <*> many (argument str (metavar "FILES/DIRS...")) - <*> optional (strOption $ long "shake-profiling" <> metavar "DIR" - <> help "Dump profiling reports to this directory") - <*> switch (long "test" - <> help "Enable additional lsp messages used by the testsuite") - <*> switch (long "example" - <> help "Include the Example Plugin. For Plugin devs only") - - <*> switch - ( long "debug" - <> short 'd' - <> help "Generate debug output" - ) - <*> optional (strOption - ( long "logfile" - <> short 'l' - <> metavar "LOGFILE" - <> help "File to log to, defaults to stdout" - )) - <*> option auto - (short 'j' - <> help "Number of threads (0: automatic)" - <> metavar "NUM" - <> value 0 - <> showDefault - ) - <*> switch (long "project-ghc-version" - <> help "Work out the project GHC version and print it") - --- --------------------------------------------------------------------- - -haskellLanguageServerNumericVersion :: String -haskellLanguageServerNumericVersion = showVersion version - -haskellLanguageServerVersion :: IO String -haskellLanguageServerVersion = do - path <- getExecutablePath - let gitHashSection = case $(gitHash) of - x | x == "UNKNOWN" -> "" - x -> " (GIT hash: " <> x <> ")" - return $ "haskell-language-server version: " <> haskellLanguageServerNumericVersion - <> " (GHC: " <> VERSION_ghc - <> ") (PATH: " <> path <> ")" - <> gitHashSection - +-- Copyright (c) 2019 The DAML Authors. All rights reserved.+-- SPDX-License-Identifier: Apache-2.0+{-# LANGUAGE CPP #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TupleSections #-}+{-# OPTIONS_GHC -Wno-dodgy-imports #-} -- GHC no longer exports def in GHC 8.6 and above++module Ide.Arguments+ ( Arguments(..)+ , GhcideArguments(..)+ , PrintVersion(..)+ , getArguments+ , haskellLanguageServerVersion+ , haskellLanguageServerNumericVersion+ ) where++import Data.Version+import Development.GitRev+import Development.IDE.Main (Command (..), commandP)+import Options.Applicative+import Paths_haskell_language_server+import System.Environment++-- ---------------------------------------------------------------------++data Arguments+ = VersionMode PrintVersion+ | ProbeToolsMode+ | Ghcide GhcideArguments+ | VSCodeExtensionSchemaMode+ | DefaultConfigurationMode++data GhcideArguments = GhcideArguments+ {argsCommand :: Command+ ,argsCwd :: Maybe FilePath+ ,argsShakeProfiling :: Maybe FilePath+ ,argsTesting :: Bool+ ,argsExamplePlugin :: Bool+ -- These next two are for compatibility with existing hie clients, allowing+ -- them to just change the name of the exe and still work.+ , argsDebugOn :: Bool+ , argsLogFile :: Maybe String+ , argsThreads :: Int+ , argsProjectGhcVersion :: Bool+ } deriving Show++data PrintVersion+ = PrintVersion+ | PrintNumericVersion+ deriving (Show, Eq, Ord)++getArguments :: String -> IO Arguments+getArguments exeName = execParser opts+ where+ opts = info ((+ VersionMode <$> printVersionParser exeName+ <|> probeToolsParser exeName+ <|> Ghcide <$> arguments+ <|> vsCodeExtensionSchemaModeParser+ <|> defaultConfigurationModeParser)+ <**> helper)+ ( fullDesc+ <> progDesc "Used as a test bed to check your IDE Client will work"+ <> header (exeName ++ " - GHC Haskell LSP server"))++printVersionParser :: String -> Parser PrintVersion+printVersionParser exeName =+ flag' PrintVersion+ (long "version" <> help ("Show " ++ exeName ++ " and GHC versions"))+ <|>+ flag' PrintNumericVersion+ (long "numeric-version" <> help ("Show numeric version of " ++ exeName))++probeToolsParser :: String -> Parser Arguments+probeToolsParser exeName =+ flag' ProbeToolsMode+ (long "probe-tools" <> help ("Show " ++ exeName ++ " version and other tools of interest"))++vsCodeExtensionSchemaModeParser :: Parser Arguments+vsCodeExtensionSchemaModeParser =+ flag' VSCodeExtensionSchemaMode+ (long "vscode-extension-schema" <> help "Print generic config schema for plugins (used in the package.json of haskell vscode extension)")++defaultConfigurationModeParser :: Parser Arguments+defaultConfigurationModeParser =+ flag' DefaultConfigurationMode+ (long "generate-default-config" <> help "Print config supported by the server with default values")++arguments :: Parser GhcideArguments+arguments = GhcideArguments+ <$> (commandP <|> lspCommand <|> checkCommand)+ <*> optional (strOption $ long "cwd" <> metavar "DIR"+ <> help "Change to this directory")+ <*> optional (strOption $ long "shake-profiling" <> metavar "DIR"+ <> help "Dump profiling reports to this directory")+ <*> switch (long "test"+ <> help "Enable additional lsp messages used by the testsuite")+ <*> switch (long "example"+ <> help "Include the Example Plugin. For Plugin devs only")++ <*> switch+ ( long "debug"+ <> short 'd'+ <> help "Generate debug output"+ )+ <*> optional (strOption+ ( long "logfile"+ <> short 'l'+ <> metavar "LOGFILE"+ <> help "File to log to, defaults to stdout"+ ))+ <*> option auto+ (short 'j'+ <> help "Number of threads (0: automatic)"+ <> metavar "NUM"+ <> value 0+ <> showDefault+ )+ <*> switch (long "project-ghc-version"+ <> help "Work out the project GHC version and print it")+ where+ lspCommand = LSP <$ flag' True (long "lsp" <> help "Start talking to an LSP server")+ checkCommand = Check <$> many (argument str (metavar "FILES/DIRS..."))++-- ---------------------------------------------------------------------++haskellLanguageServerNumericVersion :: String+haskellLanguageServerNumericVersion = showVersion version++haskellLanguageServerVersion :: IO String+haskellLanguageServerVersion = do+ path <- getExecutablePath+ let gitHashSection = case $(gitHash) of+ x | x == "UNKNOWN" -> ""+ x -> " (GIT hash: " <> x <> ")"+ return $ "haskell-language-server version: " <> haskellLanguageServerNumericVersion+ <> " (GHC: " <> VERSION_ghc+ <> ") (PATH: " <> path <> ")"+ <> gitHashSection+
@@ -1,106 +1,102 @@--- Copyright (c) 2019 The DAML Authors. All rights reserved. --- SPDX-License-Identifier: Apache-2.0 -{-# LANGUAGE CPP #-} -- To get precise GHC version -{-# OPTIONS_GHC -Wno-dodgy-imports #-} -- GHC no longer exports def in GHC 8.6 and above -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeFamilies #-} - -module Ide.Main(defaultMain, runLspMode) where - -import Control.Monad.Extra -import qualified Data.Map.Strict as Map -import qualified Data.Text as T -import Development.IDE.Core.Rules -import Development.IDE.Session (setInitialDynFlags, getHieDbLoc) -import Development.IDE.Types.Logger as G -import qualified Language.LSP.Server as LSP -import Ide.Arguments -import Ide.Logger -import Ide.Version -import Ide.Types (IdePlugins, ipMap) -import qualified System.Directory.Extra as IO -import System.Exit -import System.IO -import qualified System.Log.Logger as L -import HieDb.Run -import qualified Development.IDE.Main as Main -import qualified Development.IDE.Types.Options as Ghcide -import Development.Shake (ShakeOptions(shakeThreads)) -import Data.Default - -defaultMain :: Arguments -> IdePlugins IdeState -> IO () -defaultMain args idePlugins = do - -- WARNING: If you write to stdout before runLanguageServer - -- then the language server will not work - - hlsVer <- haskellLanguageServerVersion - case args of - ProbeToolsMode -> do - programsOfInterest <- findProgramVersions - putStrLn hlsVer - putStrLn "Tool versions found on the $PATH" - putStrLn $ showProgramVersionOfInterest programsOfInterest - - VersionMode PrintVersion -> - putStrLn hlsVer - - VersionMode PrintNumericVersion -> - putStrLn haskellLanguageServerNumericVersion - - DbCmd opts cmd -> do - dir <- IO.getCurrentDirectory - dbLoc <- getHieDbLoc dir - hPutStrLn stderr $ "Using hiedb at: " ++ dbLoc - mlibdir <- setInitialDynFlags def - case mlibdir of - Nothing -> exitWith $ ExitFailure 1 - Just libdir -> - runCommand libdir opts{database = dbLoc} cmd - - LspMode lspArgs -> do - {- see WARNING above -} - hPutStrLn stderr hlsVer - runLspMode lspArgs idePlugins - --- --------------------------------------------------------------------- - -hlsLogger :: G.Logger -hlsLogger = G.Logger $ \pri txt -> - case pri of - G.Telemetry -> logm (T.unpack txt) - G.Debug -> debugm (T.unpack txt) - G.Info -> logm (T.unpack txt) - G.Warning -> warningm (T.unpack txt) - G.Error -> errorm (T.unpack txt) - --- --------------------------------------------------------------------- - -runLspMode :: LspArguments -> IdePlugins IdeState -> IO () -runLspMode lspArgs@LspArguments{..} idePlugins = do - whenJust argsCwd IO.setCurrentDirectory - dir <- IO.getCurrentDirectory - LSP.setupLogger argsLogFile ["hls", "hie-bios"] - $ if argsDebugOn then L.DEBUG else L.INFO - - when argLSP $ do - hPutStrLn stderr "Starting (haskell-language-server)LSP server..." - hPutStrLn stderr $ " with arguments: " <> show lspArgs - hPutStrLn stderr $ " with plugins: " <> show (Map.keys $ ipMap idePlugins) - hPutStrLn stderr $ " in directory: " <> dir - hPutStrLn stderr "If you are seeing this in a terminal, you probably should have run ghcide WITHOUT the --lsp option!" - - Main.defaultMain def - { Main.argFiles = if argLSP then Nothing else Just [] - , Main.argsHlsPlugins = idePlugins - , Main.argsLogger = hlsLogger - , Main.argsIdeOptions = \_config sessionLoader -> - let defOptions = Ghcide.defaultIdeOptions sessionLoader - in defOptions - { Ghcide.optShakeProfiling = argsShakeProfiling - , Ghcide.optTesting = Ghcide.IdeTesting argsTesting - , Ghcide.optShakeOptions = (Ghcide.optShakeOptions defOptions) - {shakeThreads = argsThreads} - } - } +-- Copyright (c) 2019 The DAML Authors. All rights reserved.+-- SPDX-License-Identifier: Apache-2.0+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -Wno-dodgy-imports #-} -- GHC no longer exports def in GHC 8.6 and above+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}++module Ide.Main(defaultMain, runLspMode) where++import Control.Monad.Extra+import qualified Data.Aeson.Encode.Pretty as A+import qualified Data.ByteString.Lazy.Char8 as LBS+import Data.Default+import qualified Data.Text as T+import Development.IDE.Core.Rules+import Development.IDE.Main (isLSP)+import qualified Development.IDE.Main as Main+import Development.IDE.Types.Logger as G+import qualified Development.IDE.Types.Options as Ghcide+import Development.Shake (ShakeOptions (shakeThreads))+import Ide.Arguments+import Ide.Logger+import Ide.Plugin.ConfigUtils (pluginsToDefaultConfig,+ pluginsToVSCodeExtensionSchema)+import Ide.Types (IdePlugins, ipMap)+import Ide.Version+import qualified Language.LSP.Server as LSP+import qualified System.Directory.Extra as IO+import System.IO+import qualified System.Log.Logger as L++defaultMain :: Arguments -> IdePlugins IdeState -> IO ()+defaultMain args idePlugins = do+ -- WARNING: If you write to stdout before runLanguageServer+ -- then the language server will not work++ hlsVer <- haskellLanguageServerVersion+ case args of+ ProbeToolsMode -> do+ programsOfInterest <- findProgramVersions+ putStrLn hlsVer+ putStrLn "Tool versions found on the $PATH"+ putStrLn $ showProgramVersionOfInterest programsOfInterest++ VersionMode PrintVersion ->+ putStrLn hlsVer++ VersionMode PrintNumericVersion ->+ putStrLn haskellLanguageServerNumericVersion++ Ghcide ghcideArgs -> do+ {- see WARNING above -}+ hPutStrLn stderr hlsVer+ runLspMode ghcideArgs idePlugins++ VSCodeExtensionSchemaMode -> do+ LBS.putStrLn $ A.encodePretty $ pluginsToVSCodeExtensionSchema idePlugins++ DefaultConfigurationMode -> do+ LBS.putStrLn $ A.encodePretty $ pluginsToDefaultConfig idePlugins++-- ---------------------------------------------------------------------++hlsLogger :: G.Logger+hlsLogger = G.Logger $ \pri txt ->+ case pri of+ G.Telemetry -> logm (T.unpack txt)+ G.Debug -> debugm (T.unpack txt)+ G.Info -> logm (T.unpack txt)+ G.Warning -> warningm (T.unpack txt)+ G.Error -> errorm (T.unpack txt)++-- ---------------------------------------------------------------------++runLspMode :: GhcideArguments -> IdePlugins IdeState -> IO ()+runLspMode ghcideArgs@GhcideArguments{..} idePlugins = do+ whenJust argsCwd IO.setCurrentDirectory+ dir <- IO.getCurrentDirectory+ LSP.setupLogger argsLogFile ["hls", "hie-bios"]+ $ if argsDebugOn then L.DEBUG else L.INFO++ when (isLSP argsCommand) $ do+ hPutStrLn stderr "Starting (haskell-language-server)LSP server..."+ hPutStrLn stderr $ " with arguments: " <> show ghcideArgs+ hPutStrLn stderr $ " with plugins: " <> show (map fst $ ipMap idePlugins)+ hPutStrLn stderr $ " in directory: " <> dir++ Main.defaultMain def+ { Main.argCommand = argsCommand+ , Main.argsHlsPlugins = idePlugins+ , Main.argsLogger = pure hlsLogger+ , Main.argsIdeOptions = \_config sessionLoader ->+ let defOptions = Ghcide.defaultIdeOptions sessionLoader+ in defOptions+ { Ghcide.optShakeProfiling = argsShakeProfiling+ , Ghcide.optTesting = Ghcide.IdeTesting argsTesting+ , Ghcide.optShakeOptions = (Ghcide.optShakeOptions defOptions)+ {shakeThreads = argsThreads}+ }+ }
@@ -1,79 +1,79 @@-{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE CPP #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE OverloadedStrings #-} --- | Information and display strings for HIE's version --- and the current project's version -module Ide.Version where - -import Development.GitRev (gitCommitCount) -import Options.Applicative.Simple (simpleVersion) -import qualified Paths_haskell_language_server as Meta -import System.Info -import Data.Version -import Data.Maybe (listToMaybe) -import System.Directory -import System.Process -import System.Exit -import Text.ParserCombinators.ReadP - --- >>> hlsVersion -hlsVersion :: String -hlsVersion = - let commitCount = $gitCommitCount - in concat $ concat - [ [$(simpleVersion Meta.version)] - -- Leave out number of commits for --depth=1 clone - -- See https://github.com/commercialhaskell/stack/issues/792 - , [" (" ++ commitCount ++ " commits)" | commitCount /= ("1"::String) && - commitCount /= ("UNKNOWN" :: String)] - , [" ", arch] - , [" ", hlsGhcDisplayVersion] - ] - where - hlsGhcDisplayVersion = compilerName ++ "-" ++ VERSION_ghc - -data ProgramsOfInterest = ProgramsOfInterest - { cabalVersion :: Maybe Version - , stackVersion :: Maybe Version - , ghcVersion :: Maybe Version - } - -showProgramVersionOfInterest :: ProgramsOfInterest -> String -showProgramVersionOfInterest ProgramsOfInterest {..} = - unlines - [ concat ["cabal:\t\t", showVersionWithDefault cabalVersion] - , concat ["stack:\t\t", showVersionWithDefault stackVersion] - , concat ["ghc:\t\t", showVersionWithDefault ghcVersion] - ] - where - showVersionWithDefault :: Maybe Version -> String - showVersionWithDefault = maybe "Not found" showVersion - -findProgramVersions :: IO ProgramsOfInterest -findProgramVersions = ProgramsOfInterest - <$> findVersionOf "cabal" - <*> findVersionOf "stack" - <*> findVersionOf "ghc" - --- | Find the version of the given program. --- Assumes the program accepts the cli argument "--numeric-version". --- If the invocation has a non-zero exit-code, we return 'Nothing' -findVersionOf :: FilePath -> IO (Maybe Version) -findVersionOf tool = - findExecutable tool >>= \case - Nothing -> pure Nothing - Just path -> - readProcessWithExitCode path ["--numeric-version"] "" >>= \case - (ExitSuccess, sout, _) -> pure $ consumeParser myVersionParser sout - _ -> pure Nothing - where - myVersionParser = do - skipSpaces - version <- parseVersion - skipSpaces - pure version - - consumeParser :: ReadP a -> String -> Maybe a - consumeParser p input = listToMaybe $ map fst . filter (null . snd) $ readP_to_S p input +{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell #-}+-- | Information and display strings for HIE's version+-- and the current project's version+module Ide.Version where++import Data.Maybe (listToMaybe)+import Data.Version+import Development.GitRev (gitCommitCount)+import Options.Applicative.Simple (simpleVersion)+import qualified Paths_haskell_language_server as Meta+import System.Directory+import System.Exit+import System.Info+import System.Process+import Text.ParserCombinators.ReadP++-- >>> hlsVersion+hlsVersion :: String+hlsVersion =+ let commitCount = $gitCommitCount+ in concat $ concat+ [ [$(simpleVersion Meta.version)]+ -- Leave out number of commits for --depth=1 clone+ -- See https://github.com/commercialhaskell/stack/issues/792+ , [" (" ++ commitCount ++ " commits)" | commitCount /= ("1"::String) &&+ commitCount /= ("UNKNOWN" :: String)]+ , [" ", arch]+ , [" ", hlsGhcDisplayVersion]+ ]+ where+ hlsGhcDisplayVersion = compilerName ++ "-" ++ VERSION_ghc++data ProgramsOfInterest = ProgramsOfInterest+ { cabalVersion :: Maybe Version+ , stackVersion :: Maybe Version+ , ghcVersion :: Maybe Version+ }++showProgramVersionOfInterest :: ProgramsOfInterest -> String+showProgramVersionOfInterest ProgramsOfInterest {..} =+ unlines+ [ concat ["cabal:\t\t", showVersionWithDefault cabalVersion]+ , concat ["stack:\t\t", showVersionWithDefault stackVersion]+ , concat ["ghc:\t\t", showVersionWithDefault ghcVersion]+ ]+ where+ showVersionWithDefault :: Maybe Version -> String+ showVersionWithDefault = maybe "Not found" showVersion++findProgramVersions :: IO ProgramsOfInterest+findProgramVersions = ProgramsOfInterest+ <$> findVersionOf "cabal"+ <*> findVersionOf "stack"+ <*> findVersionOf "ghc"++-- | Find the version of the given program.+-- Assumes the program accepts the cli argument "--numeric-version".+-- If the invocation has a non-zero exit-code, we return 'Nothing'+findVersionOf :: FilePath -> IO (Maybe Version)+findVersionOf tool =+ findExecutable tool >>= \case+ Nothing -> pure Nothing+ Just path ->+ readProcessWithExitCode path ["--numeric-version"] "" >>= \case+ (ExitSuccess, sout, _) -> pure $ consumeParser myVersionParser sout+ _ -> pure Nothing+ where+ myVersionParser = do+ skipSpaces+ version <- parseVersion+ skipSpaces+ pure version++ consumeParser :: ReadP a -> String -> Maybe a+ consumeParser p input = listToMaybe $ map fst . filter (null . snd) $ readP_to_S p input
@@ -1,82 +0,0 @@-{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeOperators #-} -module Class - ( tests - ) -where - -import Control.Applicative.Combinators -import Control.Lens hiding ((<.>)) -import Control.Monad.IO.Class (MonadIO (liftIO)) -import qualified Data.ByteString.Lazy as BS -import qualified Data.Text.Encoding as T -import Language.LSP.Test -import Language.LSP.Types hiding (_command, _title) -import qualified Language.LSP.Types.Lens as J -import System.FilePath -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.Golden -import Test.Tasty.HUnit - -tests :: TestTree -tests = testGroup - "class" - [ testCase "Produces addMinimalMethodPlaceholders code actions for one instance" $ do - runSession hlsCommand fullCaps classPath $ do - doc <- openDoc "T1.hs" "haskell" - _ <- waitForDiagnosticsFromSource doc "typecheck" - caResults <- getAllCodeActions doc - liftIO $ map (^? _CACodeAction . J.title) caResults - @?= - [ Just "Add placeholders for '=='" - , Just "Add placeholders for '/='" - , Just "Disable \"missing-methods\" warnings" - ] - , glodenTest "Creates a placeholder for '=='" "T1" "eq" - $ \(eqAction:_) -> do - executeCodeAction eqAction - , glodenTest "Creates a placeholder for '/='" "T1" "ne" - $ \(_:neAction:_) -> do - executeCodeAction neAction - , glodenTest "Creates a placeholder for 'fmap'" "T2" "fmap" - $ \(_:_:fmapAction:_) -> do - executeCodeAction fmapAction - , glodenTest "Creates a placeholder for multiple methods 1" "T3" "1" - $ \(mmAction:_) -> do - executeCodeAction mmAction - , glodenTest "Creates a placeholder for multiple methods 2" "T3" "2" - $ \(_:mmAction:_) -> do - executeCodeAction mmAction - , glodenTest "Creates a placeholder for a method starting with '_'" "T4" "" - $ \(_fAction:_) -> do - executeCodeAction _fAction - ] - -_CACodeAction :: Prism' (Command |? CodeAction) CodeAction -_CACodeAction = prism' InR $ \case - InR action -> Just action - _ -> Nothing - -classPath :: FilePath -classPath = "test" </> "testdata" </> "class" - -glodenTest :: String -> FilePath -> FilePath -> ([CodeAction] -> Session ()) -> TestTree -glodenTest name fp deco execute - = goldenVsStringDiff name goldenGitDiff (classPath </> fpWithDeco <.> "expected" <.> "hs") - $ runSession hlsCommand fullCaps classPath - $ do - doc <- openDoc (fp <.> "hs") "haskell" - _ <- waitForDiagnosticsFromSource doc "typecheck" - actions <- concatMap (^.. _CACodeAction) <$> getAllCodeActions doc - execute actions - BS.fromStrict . T.encodeUtf8 <$> (skipManyTill anyMessage $ getDocumentEdit doc) - where - fpWithDeco - | deco == "" = fp - | otherwise = fp <.> deco - -goldenGitDiff :: FilePath -> FilePath -> [String] -goldenGitDiff fRef fNew = ["git", "diff", "--no-index", "--text", "--exit-code", fRef, fNew]
@@ -1,34 +1,31 @@-{-# LANGUAGE OverloadedStrings #-} -module Command (tests) where - -import Control.Lens hiding (List) -import Control.Monad.IO.Class -import qualified Data.Text as T -import Data.Char -import Language.LSP.Test -import Language.LSP.Types as LSP -import Language.LSP.Types.Lens as LSP -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.HUnit - -tests :: TestTree -tests = testGroup "commands" [ - testCase "are prefixed" $ - runSession hlsCommand fullCaps "test/testdata/" $ do - ResponseMessage _ _ (Right res) <- initializeResponse - let List cmds = res ^. LSP.capabilities . executeCommandProvider . _Just . commands - f x = (T.length (T.takeWhile isNumber x) >= 1) && (T.count ":" x >= 2) - liftIO $ do - all f cmds @? "All prefixed" - not (null cmds) @? "Commands aren't empty" - , testCase "get de-prefixed" $ - runSession hlsCommand fullCaps "test/testdata/" $ do - ResponseMessage _ _ (Left err) <- request - SWorkspaceExecuteCommand - (ExecuteCommandParams Nothing "34133:eval:evalCommand" (Just (List []))) - let ResponseError _ msg _ = err - -- We expect an error message about the dud arguments, but we can - -- check that we found the right plugin. - liftIO $ "while parsing args for evalCommand in plugin eval" `T.isInfixOf` msg @? "Has error message" - ] +{-# LANGUAGE OverloadedStrings #-}+module Command (tests) where++import Control.Lens hiding (List)+import Data.Char+import qualified Data.Text as T+import Language.LSP.Types as LSP+import Language.LSP.Types.Lens as LSP+import Test.Hls+import Test.Hls.Command++tests :: TestTree+tests = testGroup "commands" [+ testCase "are prefixed" $+ runSession hlsCommand fullCaps "test/testdata/" $ do+ ResponseMessage _ _ (Right res) <- initializeResponse+ let List cmds = res ^. LSP.capabilities . executeCommandProvider . _Just . commands+ f x = (T.length (T.takeWhile isNumber x) >= 1) && (T.count ":" x >= 2)+ liftIO $ do+ all f cmds @? "All prefixed"+ not (null cmds) @? "Commands aren't empty"+ , testCase "get de-prefixed" $+ runSession hlsCommand fullCaps "test/testdata/" $ do+ ResponseMessage _ _ (Left err) <- request+ SWorkspaceExecuteCommand+ (ExecuteCommandParams Nothing "34133:eval:evalCommand" (Just (List [])))+ let ResponseError _ msg _ = err+ -- We expect an error message about the dud arguments, but we can+ -- check that we found the right plugin.+ liftIO $ "while parsing args for evalCommand in plugin eval" `T.isInfixOf` msg @? "Has error message"+ ]
@@ -1,410 +1,404 @@-{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ScopedTypeVariables #-} -module Completion(tests) where - -import Control.Monad.IO.Class -import Control.Lens hiding ((.=)) -import Data.Aeson (object, (.=)) -import Language.LSP.Test -import Language.LSP.Types -import Language.LSP.Types.Lens hiding (applyEdit) -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.ExpectedFailure (ignoreTestBecause) -import Test.Tasty.HUnit -import qualified Data.Text as T -import Data.Default (def) -import Ide.Plugin.Config (Config (maxCompletions)) - -tests :: TestTree -tests = testGroup "completions" [ - testCase "works" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let te = TextEdit (Range (Position 5 7) (Position 5 24)) "put" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 5 9) - let item = head $ filter ((== "putStrLn") . (^. label)) compls - liftIO $ do - item ^. label @?= "putStrLn" - item ^. kind @?= Just CiFunction - item ^. detail @?= Just ":: String -> IO ()" - item ^. insertTextFormat @?= Just Snippet - item ^. insertText @?= Just "putStrLn ${1:String}" - - , ignoreTestBecause "no support for itemCompletion/resolve requests" - $ testCase "itemCompletion/resolve works" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let te = TextEdit (Range (Position 5 7) (Position 5 24)) "put" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 5 9) - let item = head $ filter ((== "putStrLn") . (^. label)) compls - resolvedRes <- request SCompletionItemResolve item - let Right resolved = resolvedRes ^. result - liftIO $ print resolved - liftIO $ do - resolved ^. label @?= "putStrLn" - resolved ^. kind @?= Just CiFunction - resolved ^. detail @?= Just "String -> IO ()\nPrelude" - resolved ^. insertTextFormat @?= Just Snippet - resolved ^. insertText @?= Just "putStrLn ${1:String}" - - , testCase "completes imports" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - _ <- waitForDiagnostics - - let te = TextEdit (Range (Position 1 17) (Position 1 26)) "Data.M" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 1 23) - let item = head $ filter ((== "Maybe") . (^. label)) compls - liftIO $ do - item ^. label @?= "Maybe" - item ^. detail @?= Just "Data.Maybe" - item ^. kind @?= Just CiModule - - , testCase "completes qualified imports" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - _ <- waitForDiagnostics - - let te = TextEdit (Range (Position 2 17) (Position 2 25)) "Data.L" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 2 24) - let item = head $ filter ((== "List") . (^. label)) compls - liftIO $ do - item ^. label @?= "List" - item ^. detail @?= Just "Data.List" - item ^. kind @?= Just CiModule - - , testCase "completes language extensions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - _ <- waitForDiagnostics - - let te = TextEdit (Range (Position 0 24) (Position 0 31)) "" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 0 24) - let item = head $ filter ((== "OverloadedStrings") . (^. label)) compls - liftIO $ do - item ^. label @?= "OverloadedStrings" - item ^. kind @?= Just CiKeyword - - , testCase "completes the Strict language extension" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - _ <- waitForDiagnostics - - let te = TextEdit (Range (Position 0 13) (Position 0 31)) "Str" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 0 16) - let item = head $ filter ((== "Strict") . (^. label)) compls - liftIO $ do - item ^. label @?= "Strict" - item ^. kind @?= Just CiKeyword - - , testCase "completes No- language extensions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - _ <- waitForDiagnostics - - let te = TextEdit (Range (Position 0 13) (Position 0 31)) "NoOverload" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 0 23) - let item = head $ filter ((== "NoOverloadedStrings") . (^. label)) compls - liftIO $ do - item ^. label @?= "NoOverloadedStrings" - item ^. kind @?= Just CiKeyword - - , testCase "completes pragmas" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - _ <- waitForDiagnostics - - let te = TextEdit (Range (Position 0 4) (Position 0 34)) "" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 0 4) - let item = head $ filter ((== "LANGUAGE") . (^. label)) compls - liftIO $ do - item ^. label @?= "LANGUAGE" - item ^. kind @?= Just CiKeyword - item ^. insertTextFormat @?= Just Snippet - item ^. insertText @?= Just "LANGUAGE ${1:extension} #-}" - - , testCase "completes pragmas no close" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let te = TextEdit (Range (Position 0 4) (Position 0 24)) "" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 0 4) - let item = head $ filter ((== "LANGUAGE") . (^. label)) compls - liftIO $ do - item ^. label @?= "LANGUAGE" - item ^. kind @?= Just CiKeyword - item ^. insertTextFormat @?= Just Snippet - item ^. insertText @?= Just "LANGUAGE ${1:extension}" - - , testCase "completes options pragma" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - _ <- waitForDiagnostics - - let te = TextEdit (Range (Position 0 4) (Position 0 34)) "OPTIONS" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 0 4) - let item = head $ filter ((== "OPTIONS_GHC") . (^. label)) compls - liftIO $ do - item ^. label @?= "OPTIONS_GHC" - item ^. kind @?= Just CiKeyword - item ^. insertTextFormat @?= Just Snippet - item ^. insertText @?= Just "OPTIONS_GHC -${1:option} #-}" - - , testCase "completes ghc options pragma values" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let te = TextEdit (Range (Position 0 0) (Position 0 0)) "{-# OPTIONS_GHC -Wno-red #-}\n" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 0 24) - let item = head $ filter ((== "Wno-redundant-constraints") . (^. label)) compls - liftIO $ do - item ^. label @?= "Wno-redundant-constraints" - item ^. kind @?= Just CiKeyword - item ^. insertTextFormat @?= Nothing - item ^. insertText @?= Nothing - - , testCase "completes with no prefix" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - compls <- getCompletions doc (Position 5 7) - liftIO $ assertBool "Expected completions" $ not $ null compls - - -- See https://github.com/haskell/haskell-ide-engine/issues/903 - , testCase "strips compiler generated stuff from completions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "DupRecFields.hs" "haskell" - - let te = TextEdit (Range (Position 5 0) (Position 5 2)) "acc" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 5 4) - let item = head $ filter (\c -> c^.label == "accessor") compls - liftIO $ do - item ^. label @?= "accessor" - item ^. kind @?= Just CiFunction - - , testCase "have implicit foralls on basic polymorphic types" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let te = TextEdit (Range (Position 5 7) (Position 5 9)) "id" - _ <- applyEdit doc te - compls <- getCompletions doc (Position 5 9) - let item = head $ filter ((== "id") . (^. label)) compls - liftIO $ do - item ^. detail @?= Just ":: a -> a" - - , testCase "have implicit foralls with multiple type variables" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let te = TextEdit (Range (Position 5 7) (Position 5 24)) "flip" - _ <- applyEdit doc te - compls <- getCompletions doc (Position 5 11) - let item = head $ filter ((== "flip") . (^. label)) compls - liftIO $ - item ^. detail @?= Just ":: (a -> b -> c) -> b -> a -> c" - - , testCase "maxCompletions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - compls <- getCompletions doc (Position 5 7) - liftIO $ length compls @?= maxCompletions def - - , contextTests - , snippetTests - ] - -snippetTests :: TestTree -snippetTests = testGroup "snippets" [ - testCase "work for argumentless constructors" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let te = TextEdit (Range (Position 5 7) (Position 5 24)) "Nothing" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 5 14) - let item = head $ filter ((== "Nothing") . (^. label)) compls - liftIO $ do - item ^. insertTextFormat @?= Just Snippet - item ^. insertText @?= Just "Nothing " - - , testCase "work for polymorphic types" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let te = TextEdit (Range (Position 5 7) (Position 5 24)) "fold" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 5 11) - let item = head $ filter ((== "foldl") . (^. label)) compls - liftIO $ do - item ^. label @?= "foldl" - item ^. kind @?= Just CiFunction - item ^. insertTextFormat @?= Just Snippet - item ^. insertText @?= Just "foldl ${1:b -> a -> b} ${2:b} ${3:t a}" - - , testCase "work for complex types" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let te = TextEdit (Range (Position 5 7) (Position 5 24)) "mapM" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 5 11) - let item = head $ filter ((== "mapM") . (^. label)) compls - liftIO $ do - item ^. label @?= "mapM" - item ^. kind @?= Just CiFunction - item ^. insertTextFormat @?= Just Snippet - item ^. insertText @?= Just "mapM ${1:a -> m b} ${2:t a}" - - , testCase "work for infix functions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let te = TextEdit (Range (Position 5 7) (Position 5 24)) "even `filte" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 5 18) - let item = head $ filter ((== "filter") . (^. label)) compls - liftIO $ do - item ^. label @?= "filter" - item ^. kind @?= Just CiFunction - item ^. insertTextFormat @?= Just PlainText - item ^. insertText @?= Nothing - - , testCase "work for infix functions in backticks" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let te = TextEdit (Range (Position 5 7) (Position 5 24)) "even `filte`" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 5 18) - let item = head $ filter ((== "filter") . (^. label)) compls - liftIO $ do - item ^. label @?= "filter" - item ^. kind @?= Just CiFunction - item ^. insertTextFormat @?= Just PlainText - item ^. insertText @?= Nothing - - , testCase "work for qualified infix functions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let te = TextEdit (Range (Position 5 7) (Position 5 24)) "\"\" `Data.List.interspe" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 5 29) - let item = head $ filter ((== "intersperse") . (^. label)) compls - liftIO $ do - item ^. label @?= "intersperse" - item ^. kind @?= Just CiFunction - item ^. insertTextFormat @?= Just PlainText - item ^. insertText @?= Nothing - - , testCase "work for qualified infix functions in backticks" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let te = TextEdit (Range (Position 5 7) (Position 5 24)) "\"\" `Data.List.interspe`" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 5 29) - let item = head $ filter ((== "intersperse") . (^. label)) compls - liftIO $ do - item ^. label @?= "intersperse" - item ^. kind @?= Just CiFunction - item ^. insertTextFormat @?= Just PlainText - item ^. insertText @?= Nothing - - , testCase "respects lsp configuration" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - let config = object [ "haskell" .= object ["completionSnippetsOn" .= False]] - - sendNotification SWorkspaceDidChangeConfiguration - (DidChangeConfigurationParams config) - - checkNoSnippets doc - - , testCase "respects client capabilities" $ runSession hlsCommand noSnippetsCaps "test/testdata/completion" $ do - doc <- openDoc "Completion.hs" "haskell" - - checkNoSnippets doc - ] - where - checkNoSnippets doc = do - let te = TextEdit (Range (Position 5 7) (Position 5 24)) "fold" - _ <- applyEdit doc te - - compls <- getCompletions doc (Position 5 11) - let item = head $ filter ((== "foldl") . (^. label)) compls - liftIO $ do - item ^. label @?= "foldl" - item ^. kind @?= Just CiFunction - item ^. insertTextFormat @?= Just PlainText - item ^. insertText @?= Nothing - - noSnippetsCaps = - ( textDocument - . _Just - . completion - . _Just - . completionItem - . _Just - . snippetSupport - ?~ False - ) - fullCaps - -contextTests :: TestTree -contextTests = testGroup "contexts" [ - testCase "only provides type suggestions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Context.hs" "haskell" - - compls <- getCompletions doc (Position 2 17) - liftIO $ do - compls `shouldContainCompl` "Integer" - compls `shouldNotContainCompl` "interact" - - , testCase "only provides value suggestions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Context.hs" "haskell" - - compls <- getCompletions doc (Position 3 10) - liftIO $ do - compls `shouldContainCompl` "abs" - compls `shouldNotContainCompl` "Applicative" - - , testCase "completes qualified type suggestions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do - doc <- openDoc "Context.hs" "haskell" - - compls <- getCompletions doc (Position 2 26) - liftIO $ do - compls `shouldNotContainCompl` "forkOn" - compls `shouldContainCompl` "MVar" - compls `shouldContainCompl` "Chan" - ] - -shouldContainCompl :: [CompletionItem] -> T.Text -> Assertion -compls `shouldContainCompl` x = - any ((== x) . (^. label)) compls - @? "Should contain completion: " ++ show x - -shouldNotContainCompl :: [CompletionItem] -> T.Text -> Assertion -compls `shouldNotContainCompl` x = - all ((/= x) . (^. label)) compls - @? "Should not contain completion: " ++ show x +{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+module Completion(tests) where++import Control.Lens hiding ((.=))+import Data.Aeson (object, (.=))+import qualified Data.Text as T+import Ide.Plugin.Config (maxCompletions)+import Language.LSP.Types.Lens hiding (applyEdit)+import Test.Hls+import Test.Hls.Command++tests :: TestTree+tests = testGroup "completions" [+ testCase "works" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let te = TextEdit (Range (Position 5 7) (Position 5 24)) "put"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 5 9)+ let item = head $ filter ((== "putStrLn") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "putStrLn"+ item ^. kind @?= Just CiFunction+ item ^. detail @?= Just ":: String -> IO ()"+ item ^. insertTextFormat @?= Just Snippet+ item ^. insertText @?= Just "putStrLn ${1:String}"++ , ignoreTestBecause "no support for itemCompletion/resolve requests"+ $ testCase "itemCompletion/resolve works" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let te = TextEdit (Range (Position 5 7) (Position 5 24)) "put"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 5 9)+ let item = head $ filter ((== "putStrLn") . (^. label)) compls+ resolvedRes <- request SCompletionItemResolve item+ let Right resolved = resolvedRes ^. result+ liftIO $ print resolved+ liftIO $ do+ resolved ^. label @?= "putStrLn"+ resolved ^. kind @?= Just CiFunction+ resolved ^. detail @?= Just "String -> IO ()\nPrelude"+ resolved ^. insertTextFormat @?= Just Snippet+ resolved ^. insertText @?= Just "putStrLn ${1:String}"++ , testCase "completes imports" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ _ <- waitForDiagnostics++ let te = TextEdit (Range (Position 1 17) (Position 1 26)) "Data.M"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 1 23)+ let item = head $ filter ((== "Maybe") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "Maybe"+ item ^. detail @?= Just "Data.Maybe"+ item ^. kind @?= Just CiModule++ , testCase "completes qualified imports" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ _ <- waitForDiagnostics++ let te = TextEdit (Range (Position 2 17) (Position 2 25)) "Data.L"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 2 24)+ let item = head $ filter ((== "List") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "List"+ item ^. detail @?= Just "Data.List"+ item ^. kind @?= Just CiModule++ , testCase "completes language extensions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ _ <- waitForDiagnostics++ let te = TextEdit (Range (Position 0 24) (Position 0 31)) ""+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 0 24)+ let item = head $ filter ((== "OverloadedStrings") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "OverloadedStrings"+ item ^. kind @?= Just CiKeyword++ , testCase "completes the Strict language extension" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ _ <- waitForDiagnostics++ let te = TextEdit (Range (Position 0 13) (Position 0 31)) "Str"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 0 16)+ let item = head $ filter ((== "Strict") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "Strict"+ item ^. kind @?= Just CiKeyword++ , testCase "completes No- language extensions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ _ <- waitForDiagnostics++ let te = TextEdit (Range (Position 0 13) (Position 0 31)) "NoOverload"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 0 23)+ let item = head $ filter ((== "NoOverloadedStrings") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "NoOverloadedStrings"+ item ^. kind @?= Just CiKeyword++ , testCase "completes pragmas" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ _ <- waitForDiagnostics++ let te = TextEdit (Range (Position 0 4) (Position 0 34)) ""+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 0 4)+ let item = head $ filter ((== "LANGUAGE") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "LANGUAGE"+ item ^. kind @?= Just CiKeyword+ item ^. insertTextFormat @?= Just Snippet+ item ^. insertText @?= Just "LANGUAGE ${1:extension} #-}"++ , testCase "completes pragmas no close" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let te = TextEdit (Range (Position 0 4) (Position 0 24)) ""+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 0 4)+ let item = head $ filter ((== "LANGUAGE") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "LANGUAGE"+ item ^. kind @?= Just CiKeyword+ item ^. insertTextFormat @?= Just Snippet+ item ^. insertText @?= Just "LANGUAGE ${1:extension}"++ , testCase "completes options pragma" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ _ <- waitForDiagnostics++ let te = TextEdit (Range (Position 0 4) (Position 0 34)) "OPTIONS"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 0 4)+ let item = head $ filter ((== "OPTIONS_GHC") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "OPTIONS_GHC"+ item ^. kind @?= Just CiKeyword+ item ^. insertTextFormat @?= Just Snippet+ item ^. insertText @?= Just "OPTIONS_GHC -${1:option} #-}"++ , testCase "completes ghc options pragma values" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let te = TextEdit (Range (Position 0 0) (Position 0 0)) "{-# OPTIONS_GHC -Wno-red #-}\n"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 0 24)+ let item = head $ filter ((== "Wno-redundant-constraints") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "Wno-redundant-constraints"+ item ^. kind @?= Just CiKeyword+ item ^. insertTextFormat @?= Nothing+ item ^. insertText @?= Nothing++ , testCase "completes with no prefix" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ compls <- getCompletions doc (Position 5 7)+ liftIO $ assertBool "Expected completions" $ not $ null compls++ -- See https://github.com/haskell/haskell-ide-engine/issues/903+ , testCase "strips compiler generated stuff from completions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "DupRecFields.hs" "haskell"++ let te = TextEdit (Range (Position 5 0) (Position 5 2)) "acc"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 5 4)+ let item = head $ filter (\c -> c^.label == "accessor") compls+ liftIO $ do+ item ^. label @?= "accessor"+ item ^. kind @?= Just CiFunction++ , testCase "have implicit foralls on basic polymorphic types" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let te = TextEdit (Range (Position 5 7) (Position 5 9)) "id"+ _ <- applyEdit doc te+ compls <- getCompletions doc (Position 5 9)+ let item = head $ filter ((== "id") . (^. label)) compls+ liftIO $ do+ item ^. detail @?= Just ":: a -> a"++ , testCase "have implicit foralls with multiple type variables" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let te = TextEdit (Range (Position 5 7) (Position 5 24)) "flip"+ _ <- applyEdit doc te+ compls <- getCompletions doc (Position 5 11)+ let item = head $ filter ((== "flip") . (^. label)) compls+ liftIO $+ item ^. detail @?= Just ":: (a -> b -> c) -> b -> a -> c"++ , testCase "maxCompletions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ compls <- getCompletions doc (Position 5 7)+ liftIO $ length compls @?= maxCompletions def++ , contextTests+ , snippetTests+ ]++snippetTests :: TestTree+snippetTests = testGroup "snippets" [+ testCase "work for argumentless constructors" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let te = TextEdit (Range (Position 5 7) (Position 5 24)) "Nothing"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 5 14)+ let item = head $ filter ((== "Nothing") . (^. label)) compls+ liftIO $ do+ item ^. insertTextFormat @?= Just Snippet+ item ^. insertText @?= Just "Nothing "++ , testCase "work for polymorphic types" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let te = TextEdit (Range (Position 5 7) (Position 5 24)) "fold"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 5 11)+ let item = head $ filter ((== "foldl") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "foldl"+ item ^. kind @?= Just CiFunction+ item ^. insertTextFormat @?= Just Snippet+ item ^. insertText @?= Just "foldl ${1:(b -> a -> b)} ${2:b} ${3:(t a)}"++ , testCase "work for complex types" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let te = TextEdit (Range (Position 5 7) (Position 5 24)) "mapM"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 5 11)+ let item = head $ filter ((== "mapM") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "mapM"+ item ^. kind @?= Just CiFunction+ item ^. insertTextFormat @?= Just Snippet+ item ^. insertText @?= Just "mapM ${1:(a -> m b)} ${2:(t a)}"++ , testCase "work for infix functions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let te = TextEdit (Range (Position 5 7) (Position 5 24)) "even `filte"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 5 18)+ let item = head $ filter ((== "filter") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "filter"+ item ^. kind @?= Just CiFunction+ item ^. insertTextFormat @?= Just PlainText+ item ^. insertText @?= Nothing++ , testCase "work for infix functions in backticks" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let te = TextEdit (Range (Position 5 7) (Position 5 24)) "even `filte`"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 5 18)+ let item = head $ filter ((== "filter") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "filter"+ item ^. kind @?= Just CiFunction+ item ^. insertTextFormat @?= Just PlainText+ item ^. insertText @?= Nothing++ , testCase "work for qualified infix functions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let te = TextEdit (Range (Position 5 7) (Position 5 24)) "\"\" `Data.List.interspe"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 5 29)+ let item = head $ filter ((== "intersperse") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "intersperse"+ item ^. kind @?= Just CiFunction+ item ^. insertTextFormat @?= Just PlainText+ item ^. insertText @?= Nothing++ , testCase "work for qualified infix functions in backticks" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let te = TextEdit (Range (Position 5 7) (Position 5 24)) "\"\" `Data.List.interspe`"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 5 29)+ let item = head $ filter ((== "intersperse") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "intersperse"+ item ^. kind @?= Just CiFunction+ item ^. insertTextFormat @?= Just PlainText+ item ^. insertText @?= Nothing++ , testCase "respects lsp configuration" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ let config = object ["haskell" .= object ["plugin" .= object ["ghcide-completions" .= object ["config" .= object ["snippetsOn" .= False]]]]]++ sendNotification SWorkspaceDidChangeConfiguration+ (DidChangeConfigurationParams config)++ checkNoSnippets doc++ , testCase "respects client capabilities" $ runSession hlsCommand noSnippetsCaps "test/testdata/completion" $ do+ doc <- openDoc "Completion.hs" "haskell"++ checkNoSnippets doc+ ]+ where+ checkNoSnippets doc = do+ let te = TextEdit (Range (Position 5 7) (Position 5 24)) "fold"+ _ <- applyEdit doc te++ compls <- getCompletions doc (Position 5 11)+ let item = head $ filter ((== "foldl") . (^. label)) compls+ liftIO $ do+ item ^. label @?= "foldl"+ item ^. kind @?= Just CiFunction+ item ^. insertTextFormat @?= Just PlainText+ item ^. insertText @?= Nothing++ noSnippetsCaps =+ ( textDocument+ . _Just+ . completion+ . _Just+ . completionItem+ . _Just+ . snippetSupport+ ?~ False+ )+ fullCaps++contextTests :: TestTree+contextTests = testGroup "contexts" [+ testCase "only provides type suggestions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Context.hs" "haskell"++ compls <- getCompletions doc (Position 2 17)+ liftIO $ do+ compls `shouldContainCompl` "Integer"+ compls `shouldNotContainCompl` "interact"++ , testCase "only provides value suggestions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Context.hs" "haskell"++ compls <- getCompletions doc (Position 3 10)+ liftIO $ do+ compls `shouldContainCompl` "abs"+ compls `shouldNotContainCompl` "Applicative"++ , testCase "completes qualified type suggestions" $ runSession hlsCommand fullCaps "test/testdata/completion" $ do+ doc <- openDoc "Context.hs" "haskell"++ compls <- getCompletions doc (Position 2 26)+ liftIO $ do+ compls `shouldNotContainCompl` "forkOn"+ compls `shouldContainCompl` "MVar"+ compls `shouldContainCompl` "Chan"+ ]++shouldContainCompl :: [CompletionItem] -> T.Text -> Assertion+compls `shouldContainCompl` x =+ any ((== x) . (^. label)) compls+ @? "Should contain completion: " ++ show x++shouldNotContainCompl :: [CompletionItem] -> T.Text -> Assertion+compls `shouldNotContainCompl` x =+ all ((/= x) . (^. label)) compls+ @? "Should not contain completion: " ++ show x
@@ -1,101 +1,96 @@-{-# LANGUAGE OverloadedStrings #-} - -module Config (tests) where - -import Control.Lens hiding (List) -import Control.Applicative.Combinators (skipManyTill) -import Control.Monad -import Control.Monad.IO.Class -import Data.Aeson -import Data.Default -import qualified Data.Map as Map -import qualified Data.Text as T -import Ide.Plugin.Config -import Language.LSP.Test as Test -import Language.LSP.Types -import qualified Language.LSP.Types.Lens as L -import System.FilePath ((</>)) -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.HUnit - -{-# ANN module ("HLint: ignore Reduce duplication"::String) #-} - -tests :: TestTree -tests = testGroup "plugin config" [ - -- Note: because the flag is treated generically in the plugin handler, we - -- do not have to test each individual plugin - hlintTests - , configTests - ] - -hlintTests :: TestTree -hlintTests = testGroup "hlint plugin enables" [ - - testCase "changing hlintOn configuration enables or disables hlint diagnostics" $ runHlintSession "" $ do - let config = def { hlintOn = True } - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config)) - - doc <- openDoc "ApplyRefact2.hs" "haskell" - testHlintDiagnostics doc - - let config' = def { hlintOn = False } - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config')) - - diags' <- waitForDiagnosticsFrom doc - - liftIO $ noHlintDiagnostics diags' - - , testCase "changing hlint plugin configuration enables or disables hlint diagnostics" $ runHlintSession "" $ do - let config = def { hlintOn = True } - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config)) - - doc <- openDoc "ApplyRefact2.hs" "haskell" - testHlintDiagnostics doc - - let config' = pluginGlobalOn config "hlint" False - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config')) - - diags' <- waitForDiagnosticsFrom doc - - liftIO $ noHlintDiagnostics diags' - - ] - where - runHlintSession :: FilePath -> Session a -> IO a - runHlintSession subdir = - failIfSessionTimeout . runSession hlsCommand fullCaps ("test/testdata/hlint" </> subdir) - - noHlintDiagnostics :: [Diagnostic] -> Assertion - noHlintDiagnostics diags = - Just "hlint" `notElem` map (^. L.source) diags @? "There are no hlint diagnostics" - - testHlintDiagnostics doc = do - diags <- waitForDiagnosticsFromSource doc "hlint" - liftIO $ length diags > 0 @? "There are hlint diagnostics" - -configTests :: TestTree -configTests = testGroup "config parsing" [ - testCase "empty object as user configuration should not send error logMessage" $ runConfigSession "" $ do - let config = object [] - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config)) - - -- Send custom request so server returns a response to prevent blocking - void $ sendNotification (SCustomMethod "non-existent-method") Null - - logNot <- skipManyTill Test.anyMessage (message SWindowLogMessage) - - liftIO $ (logNot ^. L.params . L.xtype) > MtError - || "non-existent-method" `T.isInfixOf` (logNot ^. L.params . L.message) - @? "Server sends logMessage with MessageType = Error" - ] - where - runConfigSession :: FilePath -> Session a -> IO a - runConfigSession subdir = - failIfSessionTimeout . runSession hlsCommand fullCaps ("test/testdata" </> subdir) - -pluginGlobalOn :: Config -> T.Text -> Bool -> Config -pluginGlobalOn config pid state = config' - where - pluginConfig = def { plcGlobalOn = state } - config' = def { plugins = Map.insert pid pluginConfig (plugins config) } +{-# LANGUAGE OverloadedStrings #-}++module Config (tests) where++import Control.Lens hiding (List)+import Control.Monad+import Data.Aeson+import qualified Data.Map as Map+import qualified Data.Text as T+import Ide.Plugin.Config+import Language.LSP.Test as Test+import qualified Language.LSP.Types.Lens as L+import System.FilePath ((</>))+import Test.Hls+import Test.Hls.Command++{-# ANN module ("HLint: ignore Reduce duplication"::String) #-}++tests :: TestTree+tests = testGroup "plugin config" [+ -- Note: because the flag is treated generically in the plugin handler, we+ -- do not have to test each individual plugin+ hlintTests+ , configTests+ ]++hlintTests :: TestTree+hlintTests = testGroup "hlint plugin enables" [++ testCase "changing hlintOn configuration enables or disables hlint diagnostics" $ runHlintSession "" $ do+ let config = def { hlintOn = True }+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config))++ doc <- openDoc "ApplyRefact2.hs" "haskell"+ testHlintDiagnostics doc++ let config' = def { hlintOn = False }+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config'))++ diags' <- waitForDiagnosticsFrom doc++ liftIO $ noHlintDiagnostics diags'++ , testCase "changing hlint plugin configuration enables or disables hlint diagnostics" $ runHlintSession "" $ do+ let config = def { hlintOn = True }+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config))++ doc <- openDoc "ApplyRefact2.hs" "haskell"+ testHlintDiagnostics doc++ let config' = pluginGlobalOn config "hlint" False+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config'))++ diags' <- waitForDiagnosticsFrom doc++ liftIO $ noHlintDiagnostics diags'++ ]+ where+ runHlintSession :: FilePath -> Session a -> IO a+ runHlintSession subdir =+ failIfSessionTimeout . runSession hlsCommand fullCaps ("test/testdata/hlint" </> subdir)++ noHlintDiagnostics :: [Diagnostic] -> Assertion+ noHlintDiagnostics diags =+ Just "hlint" `notElem` map (^. L.source) diags @? "There are no hlint diagnostics"++ testHlintDiagnostics doc = do+ diags <- waitForDiagnosticsFromSource doc "hlint"+ liftIO $ length diags > 0 @? "There are hlint diagnostics"++configTests :: TestTree+configTests = testGroup "config parsing" [+ testCase "empty object as user configuration should not send error logMessage" $ runConfigSession "" $ do+ let config = object []+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config))++ -- Send custom request so server returns a response to prevent blocking+ void $ sendNotification (SCustomMethod "non-existent-method") Null++ logNot <- skipManyTill Test.anyMessage (message SWindowLogMessage)++ liftIO $ (logNot ^. L.params . L.xtype) > MtError+ || "non-existent-method" `T.isInfixOf` (logNot ^. L.params . L.message)+ @? "Server sends logMessage with MessageType = Error"+ ]+ where+ runConfigSession :: FilePath -> Session a -> IO a+ runConfigSession subdir =+ failIfSessionTimeout . runSession hlsCommand fullCaps ("test/testdata" </> subdir)++pluginGlobalOn :: Config -> T.Text -> Bool -> Config+pluginGlobalOn config pid state = config'+ where+ pluginConfig = def { plcGlobalOn = state }+ config' = def { plugins = Map.insert pid pluginConfig (plugins config) }
@@ -1,176 +1,170 @@-{-# LANGUAGE CPP #-} -{-# LANGUAGE DuplicateRecordFields #-} -{-# LANGUAGE OverloadedStrings #-} -module Deferred(tests) where - -import Control.Applicative.Combinators -import Control.Monad.IO.Class -import Control.Lens hiding (List) --- import Control.Monad --- import Data.Maybe -import Language.LSP.Test -import Language.LSP.Types -import Language.LSP.Types.Lens hiding (id, message) --- import qualified Language.LSP.Types.Lens as LSP -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.ExpectedFailure (ignoreTestBecause) -import Test.Tasty.HUnit - - -tests :: TestTree -tests = testGroup "deferred responses" [ - - --TODO: DOes not compile - -- testCase "do not affect hover requests" $ runSession hlsCommand fullCaps "test/testdata" $ do - -- doc <- openDoc "FuncTest.hs" "haskell" - - -- id1 <- sendRequest TextDocumentHover (TextDocumentPositionParams doc (Position 4 2) Nothing) - - -- skipMany anyNotification - -- hoverRsp <- message :: Session HoverResponse - -- liftIO $ hoverRsp ^? result . _Just . _Just . contents @?= Nothing - -- liftIO $ hoverRsp ^. LSP.id @?= responseId id1 - - -- id2 <- sendRequest TextDocumentDocumentSymbol (DocumentSymbolParams doc Nothing) - -- symbolsRsp <- skipManyTill anyNotification message :: Session DocumentSymbolsResponse - -- liftIO $ symbolsRsp ^. LSP.id @?= responseId id2 - - -- id3 <- sendRequest TextDocumentHover (TextDocumentPositionParams doc (Position 4 2) Nothing) - -- hoverRsp2 <- skipManyTill anyNotification message :: Session HoverResponse - -- liftIO $ hoverRsp2 ^. LSP.id @?= responseId id3 - - -- let contents2 = hoverRsp2 ^? result . _Just . _Just . contents - -- liftIO $ contents2 `shouldNotSatisfy` null - - -- -- Now that we have cache the following request should be instant - -- let highlightParams = TextDocumentPositionParams doc (Position 7 0) Nothing - -- highlightRsp <- request TextDocumentDocumentHighlight highlightParams - -- let (Just (List locations)) = highlightRsp ^. result - -- liftIO $ locations @?= [ DocumentHighlight - -- { _range = Range - -- { _start = Position {_line = 7, _character = 0} - -- , _end = Position {_line = 7, _character = 2} - -- } - -- , _kind = Just HkWrite - -- } - -- , DocumentHighlight - -- { _range = Range - -- { _start = Position {_line = 7, _character = 0} - -- , _end = Position {_line = 7, _character = 2} - -- } - -- , _kind = Just HkWrite - -- } - -- , DocumentHighlight - -- { _range = Range - -- { _start = Position {_line = 5, _character = 6} - -- , _end = Position {_line = 5, _character = 8} - -- } - -- , _kind = Just HkRead - -- } - -- , DocumentHighlight - -- { _range = Range - -- { _start = Position {_line = 7, _character = 0} - -- , _end = Position {_line = 7, _character = 2} - -- } - -- , _kind = Just HkWrite - -- } - -- , DocumentHighlight - -- { _range = Range - -- { _start = Position {_line = 7, _character = 0} - -- , _end = Position {_line = 7, _character = 2} - -- } - -- , _kind = Just HkWrite - -- } - -- , DocumentHighlight - -- { _range = Range - -- { _start = Position {_line = 5, _character = 6} - -- , _end = Position {_line = 5, _character = 8} - -- } - -- , _kind = Just HkRead - -- } - -- ] - - testCase "instantly respond to failed modules with no cache" $ runSession hlsCommand fullCaps "test/testdata" $ do - doc <- openDoc "FuncTestFail.hs" "haskell" - defs <- getDefinitions doc (Position 1 11) - liftIO $ defs @?= InR [] - - -- TODO: the benefits of caching parsed modules is doubted. - -- TODO: add issue link - -- , testCase "respond to untypecheckable modules with parsed module cache" $ - -- runSession hlsCommand fullCaps "test/testdata" $ do - -- doc <- openDoc "FuncTestFail.hs" "haskell" - -- (Left (sym:_)) <- getDocumentSymbols doc - -- liftIO $ sym ^. name @?= "main" - - -- TODO does not compile - -- , testCase "returns hints as diagnostics" $ runSession hlsCommand fullCaps "test/testdata" $ do - -- _ <- openDoc "FuncTest.hs" "haskell" - - -- cwd <- liftIO getCurrentDirectory - -- let testUri = filePathToUri $ cwd </> "test/testdata/FuncTest.hs" - - -- diags <- skipManyTill loggingNotification publishDiagnosticsNotification - -- liftIO $ diags ^? params @?= (Just $ PublishDiagnosticsParams - -- { _uri = testUri - -- , _diagnostics = List - -- [ Diagnostic - -- (Range (Position 9 6) (Position 10 18)) - -- (Just DsInfo) - -- (Just (StringValue "Redundant do")) - -- (Just "hlint") - -- "Redundant do\nFound:\n do putStrLn \"hello\"\nWhy not:\n putStrLn \"hello\"\n" - -- Nothing - -- ] - -- } - -- ) - -- let args' = H.fromList [("pos", toJSON (Position 7 0)), ("file", toJSON testUri)] - -- args = List [Object args'] - -- - -- executeRsp <- request WorkspaceExecuteCommand (ExecuteCommandParams "hare:demote" (Just args) Nothing) - -- liftIO $ executeRsp ^. result @?= Just (Object H.empty) - - -- editReq <- message :: Session ApplyWorkspaceEditRequest - -- let expectedTextEdits = List [TextEdit (Range (Position 6 0) (Position 7 6)) " where\n bb = 5"] - -- expectedTextDocEdits = List [TextDocumentEdit (VersionedTextDocumentIdentifier testUri (Just 0)) expectedTextEdits] - -- liftIO $ editReq ^. params . edit @?= WorkspaceEdit - -- Nothing - -- (Just expectedTextDocEdits) - -- , multiServerTests - , multiMainTests - ] - ---TODO: Does not compile --- multiServerTests :: TestTree --- multiServerTests = testGroup "multi-server setup" [ --- testCase "doesn't have clashing commands on two servers" $ do --- let getCommands = runSession hlsCommand fullCaps "test/testdata" $ do --- rsp <- initializeResponse --- let uuids = rsp ^? result . _Just . capabilities . executeCommandProvider . _Just . commands --- return $ fromJust uuids --- List uuids1 <- getCommands --- List uuids2 <- getCommands --- liftIO $ forM_ (zip uuids1 uuids2) (uncurry shouldNotBe) --- ] - -multiMainTests :: TestTree -multiMainTests = testGroup "multiple main modules" [ - ignoreTestBecause "Broken: Unexpected ConduitParser.empty" $ - testCase "Can load one file at a time, when more than one Main module exists" - $ runSession hlsCommand fullCaps "test/testdata" $ do - _doc <- openDoc "ApplyRefact2.hs" "haskell" - _diagsRspHlint <- skipManyTill anyNotification (message STextDocumentPublishDiagnostics) - diagsRspGhc <- skipManyTill anyNotification (message STextDocumentPublishDiagnostics) - let (List diags) = diagsRspGhc ^. params . diagnostics - - liftIO $ length diags @?= 2 - - _doc2 <- openDoc "HaReRename.hs" "haskell" - _diagsRspHlint2 <- skipManyTill anyNotification (message STextDocumentPublishDiagnostics) - -- errMsg <- skipManyTill anyNotification notification :: Session ShowMessageNotification - diagsRsp2 <- skipManyTill anyNotification (message STextDocumentPublishDiagnostics) - let (List diags2) = diagsRsp2 ^. params . diagnostics - - liftIO $ show diags2 @?= "[]" - ] +{-# LANGUAGE CPP #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE OverloadedStrings #-}+module Deferred(tests) where++import Control.Lens hiding (List)+-- import Control.Monad+-- import Data.Maybe+import Language.LSP.Types.Lens hiding (id, message)+-- import qualified Language.LSP.Types.Lens as LSP+import Test.Hls+import Test.Hls.Command+++tests :: TestTree+tests = testGroup "deferred responses" [++ --TODO: DOes not compile+ -- testCase "do not affect hover requests" $ runSession hlsCommand fullCaps "test/testdata" $ do+ -- doc <- openDoc "FuncTest.hs" "haskell"++ -- id1 <- sendRequest TextDocumentHover (TextDocumentPositionParams doc (Position 4 2) Nothing)++ -- skipMany anyNotification+ -- hoverRsp <- message :: Session HoverResponse+ -- liftIO $ hoverRsp ^? result . _Just . _Just . contents @?= Nothing+ -- liftIO $ hoverRsp ^. LSP.id @?= responseId id1++ -- id2 <- sendRequest TextDocumentDocumentSymbol (DocumentSymbolParams doc Nothing)+ -- symbolsRsp <- skipManyTill anyNotification message :: Session DocumentSymbolsResponse+ -- liftIO $ symbolsRsp ^. LSP.id @?= responseId id2++ -- id3 <- sendRequest TextDocumentHover (TextDocumentPositionParams doc (Position 4 2) Nothing)+ -- hoverRsp2 <- skipManyTill anyNotification message :: Session HoverResponse+ -- liftIO $ hoverRsp2 ^. LSP.id @?= responseId id3++ -- let contents2 = hoverRsp2 ^? result . _Just . _Just . contents+ -- liftIO $ contents2 `shouldNotSatisfy` null++ -- -- Now that we have cache the following request should be instant+ -- let highlightParams = TextDocumentPositionParams doc (Position 7 0) Nothing+ -- highlightRsp <- request TextDocumentDocumentHighlight highlightParams+ -- let (Just (List locations)) = highlightRsp ^. result+ -- liftIO $ locations @?= [ DocumentHighlight+ -- { _range = Range+ -- { _start = Position {_line = 7, _character = 0}+ -- , _end = Position {_line = 7, _character = 2}+ -- }+ -- , _kind = Just HkWrite+ -- }+ -- , DocumentHighlight+ -- { _range = Range+ -- { _start = Position {_line = 7, _character = 0}+ -- , _end = Position {_line = 7, _character = 2}+ -- }+ -- , _kind = Just HkWrite+ -- }+ -- , DocumentHighlight+ -- { _range = Range+ -- { _start = Position {_line = 5, _character = 6}+ -- , _end = Position {_line = 5, _character = 8}+ -- }+ -- , _kind = Just HkRead+ -- }+ -- , DocumentHighlight+ -- { _range = Range+ -- { _start = Position {_line = 7, _character = 0}+ -- , _end = Position {_line = 7, _character = 2}+ -- }+ -- , _kind = Just HkWrite+ -- }+ -- , DocumentHighlight+ -- { _range = Range+ -- { _start = Position {_line = 7, _character = 0}+ -- , _end = Position {_line = 7, _character = 2}+ -- }+ -- , _kind = Just HkWrite+ -- }+ -- , DocumentHighlight+ -- { _range = Range+ -- { _start = Position {_line = 5, _character = 6}+ -- , _end = Position {_line = 5, _character = 8}+ -- }+ -- , _kind = Just HkRead+ -- }+ -- ]++ testCase "instantly respond to failed modules with no cache" $ runSession hlsCommand fullCaps "test/testdata" $ do+ doc <- openDoc "FuncTestFail.hs" "haskell"+ defs <- getDefinitions doc (Position 1 11)+ liftIO $ defs @?= InR []++ -- TODO: the benefits of caching parsed modules is doubted.+ -- TODO: add issue link+ -- , testCase "respond to untypecheckable modules with parsed module cache" $+ -- runSession hlsCommand fullCaps "test/testdata" $ do+ -- doc <- openDoc "FuncTestFail.hs" "haskell"+ -- (Left (sym:_)) <- getDocumentSymbols doc+ -- liftIO $ sym ^. name @?= "main"++ -- TODO does not compile+ -- , testCase "returns hints as diagnostics" $ runSession hlsCommand fullCaps "test/testdata" $ do+ -- _ <- openDoc "FuncTest.hs" "haskell"++ -- cwd <- liftIO getCurrentDirectory+ -- let testUri = filePathToUri $ cwd </> "test/testdata/FuncTest.hs"++ -- diags <- skipManyTill loggingNotification publishDiagnosticsNotification+ -- liftIO $ diags ^? params @?= (Just $ PublishDiagnosticsParams+ -- { _uri = testUri+ -- , _diagnostics = List+ -- [ Diagnostic+ -- (Range (Position 9 6) (Position 10 18))+ -- (Just DsInfo)+ -- (Just (StringValue "Redundant do"))+ -- (Just "hlint")+ -- "Redundant do\nFound:\n do putStrLn \"hello\"\nWhy not:\n putStrLn \"hello\"\n"+ -- Nothing+ -- ]+ -- }+ -- )+ -- let args' = H.fromList [("pos", toJSON (Position 7 0)), ("file", toJSON testUri)]+ -- args = List [Object args']+ --+ -- executeRsp <- request WorkspaceExecuteCommand (ExecuteCommandParams "hare:demote" (Just args) Nothing)+ -- liftIO $ executeRsp ^. result @?= Just (Object H.empty)++ -- editReq <- message :: Session ApplyWorkspaceEditRequest+ -- let expectedTextEdits = List [TextEdit (Range (Position 6 0) (Position 7 6)) " where\n bb = 5"]+ -- expectedTextDocEdits = List [TextDocumentEdit (VersionedTextDocumentIdentifier testUri (Just 0)) expectedTextEdits]+ -- liftIO $ editReq ^. params . edit @?= WorkspaceEdit+ -- Nothing+ -- (Just expectedTextDocEdits)+ -- , multiServerTests+ , multiMainTests+ ]++--TODO: Does not compile+-- multiServerTests :: TestTree+-- multiServerTests = testGroup "multi-server setup" [+-- testCase "doesn't have clashing commands on two servers" $ do+-- let getCommands = runSession hlsCommand fullCaps "test/testdata" $ do+-- rsp <- initializeResponse+-- let uuids = rsp ^? result . _Just . capabilities . executeCommandProvider . _Just . commands+-- return $ fromJust uuids+-- List uuids1 <- getCommands+-- List uuids2 <- getCommands+-- liftIO $ forM_ (zip uuids1 uuids2) (uncurry shouldNotBe)+-- ]++multiMainTests :: TestTree+multiMainTests = testGroup "multiple main modules" [+ ignoreTestBecause "Broken: Unexpected ConduitParser.empty" $+ testCase "Can load one file at a time, when more than one Main module exists"+ $ runSession hlsCommand fullCaps "test/testdata" $ do+ _doc <- openDoc "ApplyRefact2.hs" "haskell"+ _diagsRspHlint <- skipManyTill anyNotification (message STextDocumentPublishDiagnostics)+ diagsRspGhc <- skipManyTill anyNotification (message STextDocumentPublishDiagnostics)+ let (List diags) = diagsRspGhc ^. params . diagnostics++ liftIO $ length diags @?= 2++ _doc2 <- openDoc "HaReRename.hs" "haskell"+ _diagsRspHlint2 <- skipManyTill anyNotification (message STextDocumentPublishDiagnostics)+ -- errMsg <- skipManyTill anyNotification notification :: Session ShowMessageNotification+ diagsRsp2 <- skipManyTill anyNotification (message STextDocumentPublishDiagnostics)+ let (List diags2) = diagsRsp2 ^. params . diagnostics++ liftIO $ show diags2 @?= "[]"+ ]
@@ -1,69 +1,64 @@-module Definition (tests) where - -import Control.Lens -import Control.Monad.IO.Class -import Language.LSP.Test -import Language.LSP.Types -import Language.LSP.Types.Lens -import System.Directory -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.ExpectedFailure (ignoreTestBecause) -import Test.Tasty.HUnit - -tests :: TestTree -tests = testGroup "definitions" [ - - ignoreTestBecause "Broken: file:///Users/jwindsor/src/haskell-language-server/test/testdata/References.hs" $ - testCase "goto's symbols" $ runSession hlsCommand fullCaps "test/testdata" $ do - doc <- openDoc "References.hs" "haskell" - defs <- getDefinitions doc (Position 7 8) - let expRange = Range (Position 4 0) (Position 4 3) - liftIO $ defs @?= InL [Location (doc ^. uri) expRange] - - -- ----------------------------------- - - , ignoreTestBecause "Broken: file:///Users/jwindsor/src/haskell-language-server/test/testdata/Bar.hs" $ - testCase "goto's imported modules" $ runSession hlsCommand fullCaps "test/testdata/definition" $ do - doc <- openDoc "Foo.hs" "haskell" - defs <- getDefinitions doc (Position 2 8) - liftIO $ do - fp <- canonicalizePath "test/testdata/definition/Bar.hs" - defs @?= InL [Location (filePathToUri fp) zeroRange] - - , ignoreTestBecause "Broken: file:///Users/jwindsor/src/haskell-language-server/test/testdata/Bar.hs" $ - testCase "goto's exported modules" $ runSession hlsCommand fullCaps "test/testdata/definition" $ do - doc <- openDoc "Foo.hs" "haskell" - defs <- getDefinitions doc (Position 0 15) - liftIO $ do - fp <- canonicalizePath "test/testdata/definition/Bar.hs" - defs @?= InL [Location (filePathToUri fp) zeroRange] - - , ignoreTestBecause "Broken: file:///Users/jwindsor/src/haskell-language-server/test/testdata/Bar.hs" $ - testCase "goto's imported modules that are loaded" $ runSession hlsCommand fullCaps "test/testdata/definition" $ do - doc <- openDoc "Foo.hs" "haskell" - _ <- openDoc "Bar.hs" "haskell" - defs <- getDefinitions doc (Position 2 8) - liftIO $ do - fp <- canonicalizePath "test/testdata/definition/Bar.hs" - defs @?= InL [Location (filePathToUri fp) zeroRange] - - , ignoreTestBecause "Broken: file:///Users/jwindsor/src/haskell-language-server/test/testdata/Bar.hs" $ - testCase "goto's imported modules that are loaded, and then closed" $ - runSession hlsCommand fullCaps "test/testdata/definition" $ do - doc <- openDoc "Foo.hs" "haskell" - otherDoc <- openDoc "Bar.hs" "haskell" - closeDoc otherDoc - defs <- getDefinitions doc (Position 2 8) - _ <- waitForDiagnostics - liftIO $ putStrLn "D" - liftIO $ do - fp <- canonicalizePath "test/testdata/definition/Bar.hs" - defs @?= InL [Location (filePathToUri fp) zeroRange] - liftIO $ putStrLn "E" -- AZ - - noDiagnostics - ] - -zeroRange :: Range -zeroRange = Range (Position 0 0) (Position 0 0) +module Definition (tests) where++import Control.Lens+import Language.LSP.Types.Lens+import System.Directory+import Test.Hls+import Test.Hls.Command++tests :: TestTree+tests = testGroup "definitions" [++ ignoreTestBecause "Broken: file:///Users/jwindsor/src/haskell-language-server/test/testdata/References.hs" $+ testCase "goto's symbols" $ runSession hlsCommand fullCaps "test/testdata" $ do+ doc <- openDoc "References.hs" "haskell"+ defs <- getDefinitions doc (Position 7 8)+ let expRange = Range (Position 4 0) (Position 4 3)+ liftIO $ defs @?= InL [Location (doc ^. uri) expRange]++ -- -----------------------------------++ , ignoreTestBecause "Broken: file:///Users/jwindsor/src/haskell-language-server/test/testdata/Bar.hs" $+ testCase "goto's imported modules" $ runSession hlsCommand fullCaps "test/testdata/definition" $ do+ doc <- openDoc "Foo.hs" "haskell"+ defs <- getDefinitions doc (Position 2 8)+ liftIO $ do+ fp <- canonicalizePath "test/testdata/definition/Bar.hs"+ defs @?= InL [Location (filePathToUri fp) zeroRange]++ , ignoreTestBecause "Broken: file:///Users/jwindsor/src/haskell-language-server/test/testdata/Bar.hs" $+ testCase "goto's exported modules" $ runSession hlsCommand fullCaps "test/testdata/definition" $ do+ doc <- openDoc "Foo.hs" "haskell"+ defs <- getDefinitions doc (Position 0 15)+ liftIO $ do+ fp <- canonicalizePath "test/testdata/definition/Bar.hs"+ defs @?= InL [Location (filePathToUri fp) zeroRange]++ , ignoreTestBecause "Broken: file:///Users/jwindsor/src/haskell-language-server/test/testdata/Bar.hs" $+ testCase "goto's imported modules that are loaded" $ runSession hlsCommand fullCaps "test/testdata/definition" $ do+ doc <- openDoc "Foo.hs" "haskell"+ _ <- openDoc "Bar.hs" "haskell"+ defs <- getDefinitions doc (Position 2 8)+ liftIO $ do+ fp <- canonicalizePath "test/testdata/definition/Bar.hs"+ defs @?= InL [Location (filePathToUri fp) zeroRange]++ , ignoreTestBecause "Broken: file:///Users/jwindsor/src/haskell-language-server/test/testdata/Bar.hs" $+ testCase "goto's imported modules that are loaded, and then closed" $+ runSession hlsCommand fullCaps "test/testdata/definition" $ do+ doc <- openDoc "Foo.hs" "haskell"+ otherDoc <- openDoc "Bar.hs" "haskell"+ closeDoc otherDoc+ defs <- getDefinitions doc (Position 2 8)+ _ <- waitForDiagnostics+ liftIO $ putStrLn "D"+ liftIO $ do+ fp <- canonicalizePath "test/testdata/definition/Bar.hs"+ defs @?= InL [Location (filePathToUri fp) zeroRange]+ liftIO $ putStrLn "E" -- AZ++ noDiagnostics+ ]++zeroRange :: Range+zeroRange = Range (Position 0 0) (Position 0 0)
@@ -1,82 +1,76 @@-{-# LANGUAGE OverloadedStrings #-} - -module Diagnostic (tests) where - -import Control.Applicative.Combinators -import Control.Lens hiding (List) -import Control.Monad.IO.Class -import Data.Aeson (toJSON) -import qualified Data.Default -import Ide.Plugin.Config -import Language.LSP.Test hiding (message) -import Language.LSP.Types -import qualified Language.LSP.Types.Lens as LSP -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.ExpectedFailure (ignoreTestBecause) -import Test.Tasty.HUnit - --- --------------------------------------------------------------------- - -tests :: TestTree -tests = testGroup "diagnostics providers" [ - basicTests - , saveTests - , warningTests - ] - -basicTests :: TestTree -basicTests = testGroup "Diagnostics work" [ - testCase "hlint produces diagnostics" $ - runSession hlsCommand fullCaps "test/testdata/hlint" $ do - doc <- openDoc "ApplyRefact2.hs" "haskell" - diags <- waitForDiagnosticsFromSource doc "hlint" - reduceDiag <- liftIO $ inspectDiagnostic diags ["Eta reduce"] - redundantID <- liftIO $ inspectDiagnostic diags ["Redundant id"] - liftIO $ do - length diags @?= 2 - reduceDiag ^. LSP.range @?= Range (Position 1 0) (Position 1 12) - reduceDiag ^. LSP.severity @?= Just DsInfo - redundantID ^. LSP.severity @?= Just DsInfo - - , testCase "example plugin produces diagnostics" $ - runSession hlsCommandExamplePlugin fullCaps "test/testdata/hlint" $ do - doc <- openDoc "ApplyRefact2.hs" "haskell" - diags <- waitForDiagnosticsFromSource doc "example2" - reduceDiag <- liftIO $ inspectDiagnostic diags ["example2 diagnostic, hello world"] - liftIO $ do - length diags @?= 1 - reduceDiag ^. LSP.range @?= Range (Position 0 0) (Position 1 0) - reduceDiag ^. LSP.severity @?= Just DsError - ] - -warningTests :: TestTree -warningTests = testGroup "Warnings are warnings" [ - testCase "Overrides -Werror" $ - runSession hlsCommand fullCaps "test/testdata/wErrorTest" $ do - doc <- openDoc "src/WError.hs" "haskell" - [diag] <- waitForDiagnosticsFrom doc - liftIO $ diag ^. LSP.severity @?= Just DsWarning - ] - -saveTests :: TestTree -saveTests = testGroup "only diagnostics on save" [ - ignoreTestBecause "diagnosticsOnChange parameter is not supported right now" $ testCase "Respects diagnosticsOnChange setting" $ - runSession hlsCommandExamplePlugin codeActionSupportCaps "test/testdata" $ do - let config = Data.Default.def { diagnosticsOnChange = False } :: Config - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config)) - doc <- openDoc "Hover.hs" "haskell" - diags <- waitForDiagnosticsFrom doc - - liftIO $ do - length diags @?= 0 - - let te = TextEdit (Range (Position 0 0) (Position 0 13)) "" - _ <- applyEdit doc te - skipManyTill loggingNotification noDiagnostics - - sendNotification STextDocumentDidSave (DidSaveTextDocumentParams doc Nothing) - diags2 <- waitForDiagnosticsFrom doc - liftIO $ - length diags2 @?= 1 - ] +{-# LANGUAGE OverloadedStrings #-}++module Diagnostic (tests) where++import Control.Lens hiding (List)+import Data.Aeson (toJSON)+import qualified Data.Default+import Ide.Plugin.Config+import qualified Language.LSP.Types.Lens as LSP+import Test.Hls+import Test.Hls.Command++-- ---------------------------------------------------------------------++tests :: TestTree+tests = testGroup "diagnostics providers" [+ basicTests+ , saveTests+ , warningTests+ ]++basicTests :: TestTree+basicTests = testGroup "Diagnostics work" [+ testCase "hlint produces diagnostics" $+ runSession hlsCommand fullCaps "test/testdata/hlint" $ do+ doc <- openDoc "ApplyRefact2.hs" "haskell"+ diags <- waitForDiagnosticsFromSource doc "hlint"+ reduceDiag <- liftIO $ inspectDiagnostic diags ["Eta reduce"]+ redundantID <- liftIO $ inspectDiagnostic diags ["Redundant id"]+ liftIO $ do+ length diags @?= 2+ reduceDiag ^. LSP.range @?= Range (Position 1 0) (Position 1 12)+ reduceDiag ^. LSP.severity @?= Just DsInfo+ redundantID ^. LSP.severity @?= Just DsInfo++ , testCase "example plugin produces diagnostics" $+ runSession hlsCommandExamplePlugin fullCaps "test/testdata/hlint" $ do+ doc <- openDoc "ApplyRefact2.hs" "haskell"+ diags <- waitForDiagnosticsFromSource doc "example2"+ reduceDiag <- liftIO $ inspectDiagnostic diags ["example2 diagnostic, hello world"]+ liftIO $ do+ length diags @?= 1+ reduceDiag ^. LSP.range @?= Range (Position 0 0) (Position 1 0)+ reduceDiag ^. LSP.severity @?= Just DsError+ ]++warningTests :: TestTree+warningTests = testGroup "Warnings are warnings" [+ testCase "Overrides -Werror" $+ runSession hlsCommand fullCaps "test/testdata/wErrorTest" $ do+ doc <- openDoc "src/WError.hs" "haskell"+ [diag] <- waitForDiagnosticsFrom doc+ liftIO $ diag ^. LSP.severity @?= Just DsWarning+ ]++saveTests :: TestTree+saveTests = testGroup "only diagnostics on save" [+ ignoreTestBecause "diagnosticsOnChange parameter is not supported right now" $ testCase "Respects diagnosticsOnChange setting" $+ runSession hlsCommandExamplePlugin codeActionSupportCaps "test/testdata" $ do+ let config = Data.Default.def { diagnosticsOnChange = False } :: Config+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config))+ doc <- openDoc "Hover.hs" "haskell"+ diags <- waitForDiagnosticsFrom doc++ liftIO $ do+ length diags @?= 0++ let te = TextEdit (Range (Position 0 0) (Position 0 13)) ""+ _ <- applyEdit doc te+ skipManyTill loggingNotification noDiagnostics++ sendNotification STextDocumentDidSave (DidSaveTextDocumentParams doc Nothing)+ diags2 <- waitForDiagnosticsFrom doc+ liftIO $+ length diags2 @?= 1+ ]
@@ -1,185 +1,128 @@-{-# LANGUAGE OverloadedStrings, CPP #-} -module Format (tests) where - -import Control.Monad.IO.Class -import Data.Aeson -import qualified Data.ByteString.Lazy as BS -import qualified Data.Text.Encoding as T -import Language.LSP.Test -import Language.LSP.Types -import qualified Language.LSP.Types.Lens as LSP -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.Golden -import Test.Tasty.HUnit -import Control.Lens ((^.)) - -#if AGPL -import qualified Data.Text.IO as T -#endif - -tests :: TestTree -tests = testGroup "format document" [ - goldenVsStringDiff "works" goldenGitDiff "test/testdata/format/Format.formatted_document.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - doc <- openDoc "Format.hs" "haskell" - formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing) - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - , goldenVsStringDiff "works with custom tab size" goldenGitDiff "test/testdata/format/Format.formatted_document_with_tabsize.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - doc <- openDoc "Format.hs" "haskell" - formatDoc doc (FormattingOptions 5 True Nothing Nothing Nothing) - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - , rangeTests - , providerTests - , stylishHaskellTests -#if AGPL - , brittanyTests -#endif - , ormoluTests - , fourmoluTests - ] - -rangeTests :: TestTree -rangeTests = testGroup "format range" [ - goldenVsStringDiff "works" goldenGitDiff "test/testdata/format/Format.formatted_range.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - doc <- openDoc "Format.hs" "haskell" - formatRange doc (FormattingOptions 2 True Nothing Nothing Nothing) (Range (Position 5 0) (Position 7 10)) - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - , goldenVsStringDiff "works with custom tab size" goldenGitDiff "test/testdata/format/Format.formatted_range_with_tabsize.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - doc <- openDoc "Format.hs" "haskell" - formatRange doc (FormattingOptions 5 True Nothing Nothing Nothing) (Range (Position 8 0) (Position 11 19)) - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - ] - -providerTests :: TestTree -providerTests = testGroup "formatting provider" [ - testCase "respects none" $ runSessionWithConfig (formatConfig "none") hlsCommand fullCaps "test/testdata/format" $ do - doc <- openDoc "Format.hs" "haskell" - resp <- request STextDocumentFormatting $ DocumentFormattingParams Nothing doc (FormattingOptions 2 True Nothing Nothing Nothing) - liftIO $ resp ^. LSP.result @?= (Left $ ResponseError InvalidRequest "No plugin enabled for STextDocumentFormatting, available: []" Nothing) - - , testCase "respects initial" $ runSessionWithConfig (formatConfig "floskell") hlsCommand fullCaps "test/testdata/format" $ do - doc <- openDoc "Format.hs" "haskell" - formattedFloskell <- liftIO $ T.readFile "test/testdata/format/Format.floskell.initial.hs" - formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing) - documentContents doc >>= liftIO . (@?= formattedFloskell) - - , testCase "can change on the fly" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - formattedOrmolu <- liftIO $ T.readFile "test/testdata/format/Format.ormolu.formatted.hs" - formattedFloskell <- liftIO $ T.readFile "test/testdata/format/Format.floskell.formatted.hs" - formattedOrmoluPostFloskell <- liftIO $ T.readFile "test/testdata/format/Format.ormolu_post_floskell.formatted.hs" - - doc <- openDoc "Format.hs" "haskell" - - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "ormolu")) - formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing) - documentContents doc >>= liftIO . (@?= formattedOrmolu) - - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "floskell")) - formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing) - documentContents doc >>= liftIO . (@?= formattedFloskell) - - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "ormolu")) - formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing) - documentContents doc >>= liftIO . (@?= formattedOrmoluPostFloskell) - , testCase "supports both new and old configuration sections" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - formattedOrmolu <- liftIO $ T.readFile "test/testdata/format/Format.ormolu.formatted.hs" - formattedFloskell <- liftIO $ T.readFile "test/testdata/format/Format.floskell.formatted.hs" - - doc <- openDoc "Format.hs" "haskell" - - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfigOld "ormolu")) - formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing) - documentContents doc >>= liftIO . (@?= formattedOrmolu) - - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfigOld "floskell")) - formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing) - documentContents doc >>= liftIO . (@?= formattedFloskell) - ] - -stylishHaskellTests :: TestTree -stylishHaskellTests = testGroup "stylish-haskell" [ - goldenVsStringDiff "formats a document" goldenGitDiff "test/testdata/format/StylishHaskell.formatted_document.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "stylish-haskell")) - doc <- openDoc "StylishHaskell.hs" "haskell" - formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing) - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - , goldenVsStringDiff "formats a range" goldenGitDiff "test/testdata/format/StylishHaskell.formatted_range.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "stylish-haskell")) - doc <- openDoc "StylishHaskell.hs" "haskell" - formatRange doc (FormattingOptions 2 True Nothing Nothing Nothing) (Range (Position 0 0) (Position 2 21)) - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - ] - -#if AGPL -brittanyTests :: TestTree -brittanyTests = testGroup "brittany" [ - goldenVsStringDiff "formats a document with LF endings" goldenGitDiff "test/testdata/format/BrittanyLF.formatted_document.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "brittany")) - doc <- openDoc "BrittanyLF.hs" "haskell" - formatDoc doc (FormattingOptions 4 True Nothing Nothing Nothing) - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - - , goldenVsStringDiff "formats a document with CRLF endings" goldenGitDiff "test/testdata/format/BrittanyCRLF.formatted_document.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "brittany")) - doc <- openDoc "BrittanyCRLF.hs" "haskell" - formatDoc doc (FormattingOptions 4 True Nothing Nothing Nothing) - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - - , goldenVsStringDiff "formats a range with LF endings" goldenGitDiff "test/testdata/format/BrittanyLF.formatted_range.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "brittany")) - doc <- openDoc "BrittanyLF.hs" "haskell" - let range = Range (Position 1 0) (Position 2 22) - formatRange doc (FormattingOptions 4 True Nothing Nothing Nothing) range - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - - , goldenVsStringDiff "formats a range with CRLF endings" goldenGitDiff "test/testdata/format/BrittanyCRLF.formatted_range.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "brittany")) - doc <- openDoc "BrittanyCRLF.hs" "haskell" - let range = Range (Position 1 0) (Position 2 22) - formatRange doc (FormattingOptions 4 True Nothing Nothing Nothing) range - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - ] -#endif - -ormoluTests :: TestTree -ormoluTests = testGroup "ormolu" - [ goldenVsStringDiff "formats correctly" goldenGitDiff "test/testdata/format/Format.ormolu.formatted.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "ormolu")) - doc <- openDoc "Format.hs" "haskell" - formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing) - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - , goldenVsStringDiff "formats imports correctly" goldenGitDiff "test/testdata/format/Format2.ormolu.formatted.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "ormolu")) - doc <- openDoc "Format2.hs" "haskell" - formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing) - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - ] - -fourmoluTests :: TestTree -fourmoluTests = testGroup "fourmolu" - [ goldenVsStringDiff "formats correctly" goldenGitDiff "test/testdata/format/Format.fourmolu.formatted.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "fourmolu")) - doc <- openDoc "Format.hs" "haskell" - formatDoc doc (FormattingOptions 4 True Nothing Nothing Nothing) - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - , goldenVsStringDiff "formats imports correctly" goldenGitDiff "test/testdata/format/Format2.fourmolu.formatted.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "fourmolu")) - doc <- openDoc "Format2.hs" "haskell" - formatDoc doc (FormattingOptions 4 True Nothing Nothing Nothing) - BS.fromStrict . T.encodeUtf8 <$> documentContents doc - ] - -formatLspConfig :: Value -> Value -formatLspConfig provider = object [ "haskell" .= object ["formattingProvider" .= (provider :: Value)] ] - -#if AGPL --- | The same as 'formatLspConfig' but using the legacy section name -formatLspConfigOld :: Value -> Value -formatLspConfigOld provider = object [ "languageServerHaskell" .= object ["formattingProvider" .= (provider :: Value)] ] -#endif - -formatConfig :: Value -> SessionConfig -formatConfig provider = defaultConfig { lspConfig = Just (formatLspConfig provider) } - -goldenGitDiff :: FilePath -> FilePath -> [String] -goldenGitDiff fRef fNew = ["git", "diff", "--no-index", "--text", "--exit-code", fRef, fNew] +{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+module Format (tests) where++import Control.Lens ((^.))+import Control.Monad.IO.Class+import Data.Aeson+import qualified Data.ByteString.Lazy as BS+import qualified Data.Text.Encoding as T+import qualified Data.Text.IO as T+import Language.LSP.Test+import Language.LSP.Types+import qualified Language.LSP.Types.Lens as LSP+import Test.Hls+import Test.Hls.Command++tests :: TestTree+tests = testGroup "format document" [+ goldenGitDiff "works" "test/testdata/format/Format.formatted_document.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do+ doc <- openDoc "Format.hs" "haskell"+ formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing)+ BS.fromStrict . T.encodeUtf8 <$> documentContents doc+ , goldenGitDiff "works with custom tab size" "test/testdata/format/Format.formatted_document_with_tabsize.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do+ doc <- openDoc "Format.hs" "haskell"+ formatDoc doc (FormattingOptions 5 True Nothing Nothing Nothing)+ BS.fromStrict . T.encodeUtf8 <$> documentContents doc+ , rangeTests+ , providerTests+ , ormoluTests+ , fourmoluTests+ ]++rangeTests :: TestTree+rangeTests = testGroup "format range" [+ goldenGitDiff "works" "test/testdata/format/Format.formatted_range.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do+ doc <- openDoc "Format.hs" "haskell"+ formatRange doc (FormattingOptions 2 True Nothing Nothing Nothing) (Range (Position 5 0) (Position 7 10))+ BS.fromStrict . T.encodeUtf8 <$> documentContents doc+ , goldenGitDiff "works with custom tab size" "test/testdata/format/Format.formatted_range_with_tabsize.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do+ doc <- openDoc "Format.hs" "haskell"+ formatRange doc (FormattingOptions 5 True Nothing Nothing Nothing) (Range (Position 8 0) (Position 11 19))+ BS.fromStrict . T.encodeUtf8 <$> documentContents doc+ ]++providerTests :: TestTree+providerTests = testGroup "formatting provider" [+ testCase "respects none" $ runSessionWithConfig (formatConfig "none") hlsCommand fullCaps "test/testdata/format" $ do+ doc <- openDoc "Format.hs" "haskell"+ resp <- request STextDocumentFormatting $ DocumentFormattingParams Nothing doc (FormattingOptions 2 True Nothing Nothing Nothing)+ liftIO $ resp ^. LSP.result @?= Left (ResponseError InvalidRequest "No plugin enabled for STextDocumentFormatting, available: []" Nothing)++ , testCase "respects initial" $ runSessionWithConfig (formatConfig "floskell") hlsCommand fullCaps "test/testdata/format" $ do+ doc <- openDoc "Format.hs" "haskell"+ formattedFloskell <- liftIO $ T.readFile "test/testdata/format/Format.floskell.initial.hs"+ formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing)+ documentContents doc >>= liftIO . (@?= formattedFloskell)++ , testCase "can change on the fly" $ runSession hlsCommand fullCaps "test/testdata/format" $ do+ formattedOrmolu <- liftIO $ T.readFile "test/testdata/format/Format.ormolu.formatted.hs"+ formattedFloskell <- liftIO $ T.readFile "test/testdata/format/Format.floskell.formatted.hs"+ formattedOrmoluPostFloskell <- liftIO $ T.readFile "test/testdata/format/Format.ormolu_post_floskell.formatted.hs"++ doc <- openDoc "Format.hs" "haskell"++ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "ormolu"))+ formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing)+ documentContents doc >>= liftIO . (@?= formattedOrmolu)++ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "floskell"))+ formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing)+ documentContents doc >>= liftIO . (@?= formattedFloskell)++ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "ormolu"))+ formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing)+ documentContents doc >>= liftIO . (@?= formattedOrmoluPostFloskell)+ , testCase "supports both new and old configuration sections" $ runSession hlsCommand fullCaps "test/testdata/format" $ do+ formattedOrmolu <- liftIO $ T.readFile "test/testdata/format/Format.ormolu.formatted.hs"+ formattedFloskell <- liftIO $ T.readFile "test/testdata/format/Format.floskell.formatted.hs"++ doc <- openDoc "Format.hs" "haskell"++ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfigOld "ormolu"))+ formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing)+ documentContents doc >>= liftIO . (@?= formattedOrmolu)++ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfigOld "floskell"))+ formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing)+ documentContents doc >>= liftIO . (@?= formattedFloskell)+ ]+++ormoluTests :: TestTree+ormoluTests = testGroup "ormolu"+ [ goldenGitDiff "formats correctly" "test/testdata/format/Format.ormolu.formatted.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "ormolu"))+ doc <- openDoc "Format.hs" "haskell"+ formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing)+ BS.fromStrict . T.encodeUtf8 <$> documentContents doc+ , goldenGitDiff "formats imports correctly" "test/testdata/format/Format2.ormolu.formatted.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "ormolu"))+ doc <- openDoc "Format2.hs" "haskell"+ formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing)+ BS.fromStrict . T.encodeUtf8 <$> documentContents doc+ ]++fourmoluTests :: TestTree+fourmoluTests = testGroup "fourmolu"+ [ goldenGitDiff "formats correctly" "test/testdata/format/Format.fourmolu.formatted.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "fourmolu"))+ doc <- openDoc "Format.hs" "haskell"+ formatDoc doc (FormattingOptions 4 True Nothing Nothing Nothing)+ BS.fromStrict . T.encodeUtf8 <$> documentContents doc+ , goldenGitDiff "formats imports correctly" "test/testdata/format/Format2.fourmolu.formatted.hs" $ runSession hlsCommand fullCaps "test/testdata/format" $ do+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "fourmolu"))+ doc <- openDoc "Format2.hs" "haskell"+ formatDoc doc (FormattingOptions 4 True Nothing Nothing Nothing)+ BS.fromStrict . T.encodeUtf8 <$> documentContents doc+ ]++formatLspConfig :: Value -> Value+formatLspConfig provider = object [ "haskell" .= object ["formattingProvider" .= (provider :: Value)] ]++-- | The same as 'formatLspConfig' but using the legacy section name+formatLspConfigOld :: Value -> Value+formatLspConfigOld provider = object [ "languageServerHaskell" .= object ["formattingProvider" .= (provider :: Value)] ]++formatConfig :: Value -> SessionConfig+formatConfig provider = defaultConfig { lspConfig = Just (formatLspConfig provider) }
@@ -1,40 +1,38 @@-{-# LANGUAGE OverloadedStrings #-} - -module FunctionalBadProject (tests) where - --- import Control.Lens hiding (List) --- import Control.Monad.IO.Class --- import qualified Data.Text as T --- import Language.LSP.Test hiding (message) --- import Language.LSP.Types as LSP --- import Language.LSP.Types.Lens as LSP hiding (contents, error ) --- import Test.Hls.Util -import Test.Tasty -import Test.Tasty.HUnit - --- --------------------------------------------------------------------- --- TODO: Currently this can not succeed, since such an error is thrown in "runActionWithContext" which --- can produce diagnostics at the moment. Needs more investigation --- TODO: @fendor: Add issue link here --- -tests :: TestTree -tests = testGroup "behaviour on malformed projects" [ - testCase "no test executed" $ True @?= True - ] - - -- testCase "deals with cabal file with unsatisfiable dependency" $ - -- runSession hlsCommandExamplePlugin codeActionSupportCaps "test/testdata/badProjects/cabal" $ do - -- _doc <- openDoc "Foo.hs" "haskell" - - -- diags@(d:_) <- waitForDiagnosticsSource "bios" - -- -- liftIO $ show diags @?= "" - -- -- liftIO $ putStrLn $ show diags - -- -- liftIO $ putStrLn "a" - -- liftIO $ do - -- length diags @?= 1 - -- d ^. range @?= Range (Position 0 0) (Position 1 0) - -- d ^. severity @?= (Just DsError) - -- d ^. code @?= Nothing - -- d ^. source @?= Just "bios" - -- d ^. message @?= - -- (T.pack "readCreateProcess: stack \"build\" \"--only-configure\" \".\" (exit 1): failed\n") +{-# LANGUAGE OverloadedStrings #-}++module FunctionalBadProject (tests) where++-- import Control.Lens hiding (List)+-- import Control.Monad.IO.Class+-- import qualified Data.Text as T+-- import Language.LSP.Test hiding (message)+-- import Language.LSP.Types as LSP+-- import Language.LSP.Types.Lens as LSP hiding (contents, error )+import Test.Hls++-- ---------------------------------------------------------------------+-- TODO: Currently this can not succeed, since such an error is thrown in "runActionWithContext" which+-- can produce diagnostics at the moment. Needs more investigation+-- TODO: @fendor: Add issue link here+--+tests :: TestTree+tests = testGroup "behaviour on malformed projects" [+ testCase "no test executed" $ True @?= True+ ]++ -- testCase "deals with cabal file with unsatisfiable dependency" $+ -- runSession hlsCommandExamplePlugin codeActionSupportCaps "test/testdata/badProjects/cabal" $ do+ -- _doc <- openDoc "Foo.hs" "haskell"++ -- diags@(d:_) <- waitForDiagnosticsSource "bios"+ -- -- liftIO $ show diags @?= ""+ -- -- liftIO $ putStrLn $ show diags+ -- -- liftIO $ putStrLn "a"+ -- liftIO $ do+ -- length diags @?= 1+ -- d ^. range @?= Range (Position 0 0) (Position 1 0)+ -- d ^. severity @?= (Just DsError)+ -- d ^. code @?= Nothing+ -- d ^. source @?= Just "bios"+ -- d ^. message @?=+ -- (T.pack "readCreateProcess: stack \"build\" \"--only-configure\" \".\" (exit 1): failed\n")
@@ -1,678 +1,700 @@-{-# LANGUAGE CPP #-} -{-# LANGUAGE DuplicateRecordFields #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedStrings #-} - -module FunctionalCodeAction (tests) where - -import Control.Applicative.Combinators -import Control.Lens hiding (List) -import Control.Monad -import Control.Monad.IO.Class -import Data.Aeson -import Data.Default -import qualified Data.HashMap.Strict as HM -import Data.List -import Data.Maybe -import qualified Data.Text as T -import Ide.Plugin.Config -import Language.LSP.Test as Test -import Language.LSP.Types -import qualified Language.LSP.Types.Capabilities as C -import qualified Language.LSP.Types.Lens as L -import Test.Hls.Util -import Test.Hspec.Expectations - -import System.FilePath ((</>)) -import System.IO.Extra (withTempDir) -import Test.Tasty -import Test.Tasty.ExpectedFailure (expectFailBecause, - ignoreTestBecause) -import Test.Tasty.HUnit - -{-# ANN module ("HLint: ignore Reduce duplication"::String) #-} - -tests :: TestTree -tests = testGroup "code actions" [ - hlintTests - , importTests - , missingPragmaTests - , disableWarningTests - , packageTests - , redundantImportTests - , renameTests - , signatureTests - , typedHoleTests - , unusedTermTests - ] - - -hlintTests :: TestTree -hlintTests = testGroup "hlint suggestions" [ - testCase "provides 3.8 code actions including apply all" $ runHlintSession "" $ do - doc <- openDoc "ApplyRefact2.hs" "haskell" - diags@(reduceDiag:_) <- waitForDiagnosticsFromSource doc "hlint" - - liftIO $ do - length diags @?= 2 -- "Eta Reduce" and "Redundant Id" - reduceDiag ^. L.range @?= Range (Position 1 0) (Position 1 12) - reduceDiag ^. L.severity @?= Just DsInfo - reduceDiag ^. L.code @?= Just (InR "refact:Eta reduce") - reduceDiag ^. L.source @?= Just "hlint" - - cas <- map fromAction <$> getAllCodeActions doc - - let applyAll = find (\ca -> "Apply all hints" `T.isSuffixOf` (ca ^. L.title)) cas - let redId = find (\ca -> "Redundant id" `T.isSuffixOf` (ca ^. L.title)) cas - let redEta = find (\ca -> "Eta reduce" `T.isSuffixOf` (ca ^. L.title)) cas - - liftIO $ isJust applyAll @? "There is 'Apply all hints' code action" - liftIO $ isJust redId @? "There is 'Redundant id' code action" - liftIO $ isJust redEta @? "There is 'Eta reduce' code action" - - executeCodeAction (fromJust redId) - - contents <- skipManyTill anyMessage $ getDocumentEdit doc - liftIO $ contents @?= "main = undefined\nfoo x = x\n" - - , testCase "falls back to pre 3.8 code actions" $ runSession hlsCommand noLiteralCaps "test/testdata/hlint" $ do - doc <- openDoc "ApplyRefact2.hs" "haskell" - - _ <- waitForDiagnosticsFromSource doc "hlint" - - cars <- getAllCodeActions doc - etaReduce <- liftIO $ inspectCommand cars ["Eta reduce"] - - executeCommand etaReduce - - contents <- skipManyTill anyMessage $ getDocumentEdit doc - liftIO $ contents @?= "main = undefined\nfoo = id\n" - - , testCase "changing configuration enables or disables hlint diagnostics" $ runHlintSession "" $ do - let config = def { hlintOn = True } - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config)) - - doc <- openDoc "ApplyRefact2.hs" "haskell" - testHlintDiagnostics doc - - let config' = def { hlintOn = False } - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config')) - - diags' <- waitForDiagnosticsFrom doc - - liftIO $ noHlintDiagnostics diags' - - , testCase "changing document contents updates hlint diagnostics" $ runHlintSession "" $ do - doc <- openDoc "ApplyRefact2.hs" "haskell" - testHlintDiagnostics doc - - let change = TextDocumentContentChangeEvent - (Just (Range (Position 1 8) (Position 1 12))) - Nothing "x" - changeDoc doc [change] - expectNoMoreDiagnostics 3 doc "hlint" - - let change' = TextDocumentContentChangeEvent - (Just (Range (Position 1 8) (Position 1 12))) - Nothing "id x" - changeDoc doc [change'] - testHlintDiagnostics doc - - , knownBrokenForGhcVersions [GHC88, GHC86] "hlint doesn't take in account cpp flag as ghc -D argument" $ - testCase "hlint diagnostics works with CPP via ghc -XCPP argument (#554)" $ runHlintSession "cpp" $ do - doc <- openDoc "ApplyRefact3.hs" "haskell" - testHlintDiagnostics doc - - , knownBrokenForGhcVersions [GHC88, GHC86] "hlint doesn't take in account cpp flag as ghc -D argument" $ - testCase "hlint diagnostics works with CPP via language pragma (#554)" $ runHlintSession "" $ do - doc <- openDoc "ApplyRefact3.hs" "haskell" - testHlintDiagnostics doc - - , testCase "hlint diagnostics works with CPP via -XCPP argument and flag via #include header (#554)" $ runHlintSession "cpp" $ do - doc <- openDoc "ApplyRefact2.hs" "haskell" - testHlintDiagnostics doc - - , testCase "apply-refact works with -XLambdaCase argument (#590)" $ runHlintSession "lambdacase" $ do - testRefactor "ApplyRefact1.hs" "Redundant bracket" - expectedLambdaCase - - , testCase "apply-refact works with -XTypeApplications argument (#1242)" $ runHlintSession "typeapps" $ do - testRefactor "ApplyRefact1.hs" "Redundant bracket" - expectedTypeApp - - , testCase "apply hints works with LambdaCase via language pragma" $ runHlintSession "" $ do - testRefactor "ApplyRefact1.hs" "Redundant bracket" - ("{-# LANGUAGE LambdaCase #-}" : expectedLambdaCase) - - , expectFailBecause "apply-refact doesn't work with cpp" $ - testCase "apply hints works with CPP via -XCPP argument" $ runHlintSession "cpp" $ do - testRefactor "ApplyRefact3.hs" "Redundant bracket" - expectedCPP - - , expectFailBecause "apply-refact doesn't work with cpp" $ - testCase "apply hints works with CPP via language pragma" $ runHlintSession "" $ do - testRefactor "ApplyRefact3.hs" "Redundant bracket" - ("{-# LANGUAGE CPP #-}" : expectedCPP) - - , testCase "hlint diagnostics ignore hints honouring .hlint.yaml" $ runHlintSession "ignore" $ do - doc <- openDoc "ApplyRefact.hs" "haskell" - expectNoMoreDiagnostics 3 doc "hlint" - - , testCase "hlint diagnostics ignore hints honouring ANN annotations" $ runHlintSession "" $ do - doc <- openDoc "ApplyRefact4.hs" "haskell" - expectNoMoreDiagnostics 3 doc "hlint" - - , knownBrokenForGhcVersions [GHC810] "hlint plugin doesn't honour HLINT annotations (#838)" $ - testCase "hlint diagnostics ignore hints honouring HLINT annotations" $ runHlintSession "" $ do - doc <- openDoc "ApplyRefact5.hs" "haskell" - expectNoMoreDiagnostics 3 doc "hlint" - - , testCase "apply-refact preserve regular comments" $ runHlintSession "" $ do - testRefactor "ApplyRefact6.hs" "Redundant bracket" expectedComments - ] - where - runHlintSession :: FilePath -> Session a -> IO a - runHlintSession subdir = - failIfSessionTimeout . runSession hlsCommand fullCaps ("test/testdata/hlint" </> subdir) - - noHlintDiagnostics :: [Diagnostic] -> Assertion - noHlintDiagnostics diags = - Just "hlint" `notElem` map (^. L.source) diags @? "There are no hlint diagnostics" - - testHlintDiagnostics doc = do - diags <- waitForDiagnosticsFromSource doc "hlint" - liftIO $ length diags > 0 @? "There are hlint diagnostics" - - testRefactor file caTitle expected = do - doc <- openDoc file "haskell" - testHlintDiagnostics doc - - cas <- map fromAction <$> getAllCodeActions doc - let ca = find (\ca -> caTitle `T.isSuffixOf` (ca ^. L.title)) cas - liftIO $ isJust ca @? ("There is '" ++ T.unpack caTitle ++"' code action") - - executeCodeAction (fromJust ca) - - contents <- skipManyTill anyMessage $ getDocumentEdit doc - liftIO $ contents @?= T.unlines expected - - expectedLambdaCase = [ "module ApplyRefact1 where", "" - , "f = \\case \"true\" -> True" - , " _ -> False" - ] - expectedCPP = [ "module ApplyRefact3 where", "" - , "#ifdef FLAG" - , "f = 1" - , "#else" - , "g = 2" - , "#endif", "" - ] - expectedComments = [ "-- comment before header" - , "module ApplyRefact6 where", "" - , "{-# standalone annotation #-}", "" - , "-- standalone comment", "" - , "-- | haddock comment" - , "f = {- inline comment -}{- inline comment inside refactored code -} 1 -- ending comment", "" - , "-- final comment" - ] - expectedTypeApp = [ "module ApplyRefact1 where", "" - , "a = id @Int 1" - ] -renameTests :: TestTree -renameTests = testGroup "rename suggestions" [ - testCase "works" $ runSession hlsCommand noLiteralCaps "test/testdata" $ do - doc <- openDoc "CodeActionRename.hs" "haskell" - - _ <- waitForDiagnosticsFromSource doc "typecheck" - - cars <- getAllCodeActions doc - replaceButStrLn <- liftIO $ inspectCommand cars ["Replace with", "putStrLn"] - executeCommand replaceButStrLn - _ <- anyRequest - - x:_ <- T.lines <$> documentContents doc - liftIO $ x @?= "main = putStrLn \"hello\"" - - , testCase "doesn't give both documentChanges and changes" - $ runSession hlsCommand noLiteralCaps "test/testdata" $ do - doc <- openDoc "CodeActionRename.hs" "haskell" - - _ <- waitForDiagnosticsFromSource doc "typecheck" - - cars <- getAllCodeActions doc - cmd <- liftIO $ inspectCommand cars ["Replace with", "putStrLn"] - let Just (List [Object args]) = cmd ^. L.arguments - Object editParams = args HM.! "fallbackWorkspaceEdit" - liftIO $ do - "changes" `HM.member` editParams @? "Contains changes" - not ("documentChanges" `HM.member` editParams) @? "Doesn't contain documentChanges" - - executeCommand cmd - _ <- anyRequest - - x1:x2:_ <- T.lines <$> documentContents doc - liftIO $ - x1 == "main = putStrLn \"hello\"" - || x2 == "foo = putStrLn \"world\"" - @? "One of the typos got fixed" - ] - -importTests :: TestTree -importTests = testGroup "import suggestions" [ - testCase "works with 3.8 code action kinds" $ runSession hlsCommand fullCaps "test/testdata" $ do - doc <- openDoc "CodeActionImport.hs" "haskell" - -- No Formatting: - let config = def { formattingProvider = "none" } - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config)) - - (diag:_) <- waitForDiagnosticsFrom doc - liftIO $ diag ^. L.message @?= "Variable not in scope: when :: Bool -> IO () -> IO ()" - - actionsOrCommands <- getAllCodeActions doc - let actns = map fromAction actionsOrCommands - - importControlMonad <- liftIO $ inspectCodeAction actionsOrCommands ["import Control.Monad"] - liftIO $ do - expectCodeAction actionsOrCommands ["import Control.Monad (when)"] - forM_ actns $ \a -> do - a ^. L.kind @?= Just CodeActionQuickFix - length actns >= 10 @? "There are some actions" - - executeCodeAction importControlMonad - - contents <- documentContents doc - liftIO $ contents @?= "import Control.Monad\nmain :: IO ()\nmain = when True $ putStrLn \"hello\"" - ] - -packageTests :: TestTree -packageTests = testGroup "add package suggestions" [ - ignoreTestBecause "no support for adding dependent packages via code action" $ testCase "adds to .cabal files" $ do - flushStackEnvironment - runSession hlsCommand fullCaps "test/testdata/addPackageTest/cabal-exe" $ do - doc <- openDoc "AddPackage.hs" "haskell" - - -- ignore the first empty hlint diagnostic publish - [_,diag:_] <- count 2 $ waitForDiagnosticsFrom doc - - let prefixes = [ "Could not load module `Data.Text'" -- Windows && GHC >= 8.6 - , "Could not find module `Data.Text'" -- Windows - , "Could not load module ‘Data.Text’" -- GHC >= 8.6 - , "Could not find module ‘Data.Text’" - ] - in liftIO $ any (`T.isPrefixOf` (diag ^. L.message)) prefixes @? "Contains prefix" - - acts <- getAllCodeActions doc - let (InR action:_) = acts - - liftIO $ do - action ^. L.title @?= "Add text as a dependency" - action ^. L.kind @?= Just CodeActionQuickFix - "package:add" `T.isSuffixOf` (action ^. L.command . _Just . L.command) @? "Command contains package:add" - - executeCodeAction action - - contents <- skipManyTill anyMessage $ getDocumentEdit . TextDocumentIdentifier =<< getDocUri "add-package-test.cabal" - liftIO $ - any (\l -> "text -any" `T.isSuffixOf` l || "text : {} -any" `T.isSuffixOf` l) (T.lines contents) @? "Contains text package" - - , ignoreTestBecause "no support for adding dependent packages via code action" $ testCase "adds to hpack package.yaml files" $ - runSession hlsCommand fullCaps "test/testdata/addPackageTest/hpack-exe" $ do - doc <- openDoc "app/Asdf.hs" "haskell" - - -- ignore the first empty hlint diagnostic publish - [_,_:diag:_] <- count 2 $ waitForDiagnosticsFrom doc - - let prefixes = [ "Could not load module `Codec.Compression.GZip'" -- Windows && GHC >= 8.6 - , "Could not find module `Codec.Compression.GZip'" -- Windows - , "Could not load module ‘Codec.Compression.GZip’" -- GHC >= 8.6 - , "Could not find module ‘Codec.Compression.GZip’" - ] - in liftIO $ any (`T.isPrefixOf` (diag ^. L.message)) prefixes @? "Diagnostic contains message" - - mActions <- getAllCodeActions doc - let allActions = map fromAction mActions - action = head allActions - - liftIO $ do - action ^. L.title @?= "Add zlib as a dependency" - forM_ allActions $ \a -> a ^. L.kind @?= Just CodeActionQuickFix - forM_ allActions $ \a -> "package:add" `T.isSuffixOf` (a ^. L.command . _Just . L.command) @? "Command contains package:add" - - executeCodeAction action - - contents <- skipManyTill anyMessage $ getDocumentEdit . TextDocumentIdentifier =<< getDocUri "package.yaml" - liftIO $ do - "zlib" `T.isSuffixOf` (T.lines contents !! 3) @? "Contains zlib" - "zlib" `T.isSuffixOf` (T.lines contents !! 21) @? "Does not contain zlib in unrelated component" - ] - -redundantImportTests :: TestTree -redundantImportTests = testGroup "redundant import code actions" [ - testCase "remove solitary redundant imports" $ - runSession hlsCommand fullCaps "test/testdata/redundantImportTest/" $ do - doc <- openDoc "src/CodeActionRedundant.hs" "haskell" - - diags <- waitForDiagnosticsFromSource doc "typecheck" - liftIO $ expectDiagnostic diags ["The import of", "Data.List", "is redundant"] - - mActions <- getAllCodeActions doc - - let allActions = map fromAction mActions - actionTitles = map (view L.title) allActions - - liftIO $ actionTitles `shouldContain` ["Remove import", "Remove all redundant imports"] - - let Just removeAction = find (\x -> x ^. L.title == "Remove import") allActions - - liftIO $ do - forM_ allActions $ \a -> a ^. L.kind @?= Just CodeActionQuickFix - forM_ allActions $ \a -> a ^. L.command @?= Nothing - forM_ allActions $ \a -> isJust (a ^. L.edit) @? "Has edit" - - executeCodeAction removeAction - - -- No command/applyworkspaceedit should be here, since action - -- provides workspace edit property which skips round trip to - -- the server - contents <- documentContents doc - liftIO $ contents @?= "{-# OPTIONS_GHC -Wunused-imports #-}\nmodule CodeActionRedundant where\nmain :: IO ()\nmain = putStrLn \"hello\"\n" - - , testCase "doesn't touch other imports" $ runSession hlsCommand noLiteralCaps "test/testdata/redundantImportTest/" $ do - doc <- openDoc "src/MultipleImports.hs" "haskell" - _ <- waitForDiagnosticsFromSource doc "typecheck" - InL cmd : _ <- getAllCodeActions doc - executeCommand cmd - _ <- anyRequest - contents <- documentContents doc - liftIO $ T.lines contents @?= - [ "{-# OPTIONS_GHC -Wunused-imports #-}" - , "module MultipleImports where" - , "import Data.Maybe" - , "foo :: Int" - , "foo = fromJust (Just 3)" - ] - ] - -typedHoleTests :: TestTree -typedHoleTests = testGroup "typed hole code actions" [ - testCase "works" $ - runSession hlsCommand fullCaps "test/testdata" $ do - doc <- openDoc "TypedHoles.hs" "haskell" - _ <- waitForDiagnosticsFromSource doc "typecheck" - cas <- getAllCodeActions doc - liftIO $ do - expectCodeAction cas ["replace _ with minBound"] - expectCodeAction cas ["replace _ with foo _"] - replaceWithMaxBound <- liftIO $ inspectCodeAction cas ["replace _ with maxBound"] - - executeCodeAction replaceWithMaxBound - - contents <- documentContents doc - - liftIO $ contents @?= T.concat - [ "module TypedHoles where\n" - , "foo :: [Int] -> Int\n" - , "foo x = maxBound" - ] - - , testCase "shows more suggestions" $ - runSession hlsCommand fullCaps "test/testdata" $ do - doc <- openDoc "TypedHoles2.hs" "haskell" - _ <- waitForDiagnosticsFromSource doc "typecheck" - cas <- getAllCodeActions doc - - liftIO $ do - expectCodeAction cas ["replace _ with foo2 _"] - expectCodeAction cas ["replace _ with A _"] - replaceWithStuff <- liftIO $ inspectCodeAction cas ["replace _ with stuff _"] - - executeCodeAction replaceWithStuff - - contents <- documentContents doc - - liftIO $ T.lines contents @?= - [ "module TypedHoles2 (foo2) where" - , "newtype A = A Int" - , "foo2 :: [A] -> A" - , "foo2 x = (stuff _)" - , " where" - , " stuff (A a) = A (a + 1)" - ] - ] - -signatureTests :: TestTree -signatureTests = testGroup "missing top level signature code actions" [ - testCase "Adds top level signature" $ - runSession hlsCommand fullCaps "test/testdata/" $ do - doc <- openDoc "TopLevelSignature.hs" "haskell" - - _ <- waitForDiagnosticsFromSource doc "typecheck" - cas <- map fromAction <$> getAllCodeActions doc - - liftIO $ "add signature: main :: IO ()" `elem` map (^. L.title) cas @? "Contains code action" - - executeCodeAction $ head cas - - contents <- documentContents doc - - let expected = [ "{-# OPTIONS_GHC -Wall #-}" - , "module TopLevelSignature where" - , "main :: IO ()" - , "main = do" - , " putStrLn \"Hello\"" - , " return ()" - ] - - liftIO $ T.lines contents @?= expected - ] - -missingPragmaTests :: TestTree -missingPragmaTests = testGroup "missing pragma warning code actions" [ - testCase "Adds TypeSynonymInstances pragma" $ do - runSession hlsCommand fullCaps "test/testdata/addPragmas" $ do - doc <- openDoc "NeedsPragmas.hs" "haskell" - - _ <- waitForDiagnosticsFromSource doc "typecheck" - cas <- map fromAction <$> getAllCodeActions doc - - liftIO $ "Add \"TypeSynonymInstances\"" `elem` map (^. L.title) cas @? "Contains TypeSynonymInstances code action" - liftIO $ "Add \"FlexibleInstances\"" `elem` map (^. L.title) cas @? "Contains FlexibleInstances code action" - - executeCodeAction $ head cas - - contents <- documentContents doc - - let expected = [ "{-# LANGUAGE TypeSynonymInstances #-}" - , "module NeedsPragmas where" - , "" - , "import GHC.Generics" - , "" - , "main = putStrLn \"hello\"" - , "" - , "type Foo = Int" - , "" - , "instance Show Foo where" - , " show x = undefined" - , "" - , "instance Show (Int,String) where" - , " show = undefined" - , "" - , "data FFF a = FFF Int String a" - , " deriving (Generic,Functor,Traversable)" - ] - - liftIO $ T.lines contents @?= expected - - , testCase "Adds TypeApplications pragma" $ do - runSession hlsCommand fullCaps "test/testdata/addPragmas" $ do - doc <- openDoc "TypeApplications.hs" "haskell" - - _ <- waitForDiagnosticsFrom doc - cas <- map fromAction <$> getAllCodeActions doc - - liftIO $ "Add \"TypeApplications\"" `elem` map (^. L.title) cas @? "Contains TypeApplications code action" - - executeCodeAction $ head cas - - contents <- documentContents doc - - let expected = --- TODO: Why CPP??? -#if __GLASGOW_HASKELL__ < 810 - [ "{-# LANGUAGE ScopedTypeVariables #-}" - , "{-# LANGUAGE TypeApplications #-}" -#else - [ "{-# LANGUAGE TypeApplications #-}" - , "{-# LANGUAGE ScopedTypeVariables #-}" -#endif - , "module TypeApplications where" - , "" - , "foo :: forall a. a -> a" - , "foo = id @a" - ] - - liftIO $ T.lines contents @?= expected - , testCase "No duplication" $ do - runSession hlsCommand fullCaps "test/testdata/addPragmas" $ do - doc <- openDoc "NamedFieldPuns.hs" "haskell" - - _ <- waitForDiagnosticsFrom doc - cas <- map fromAction <$> getCodeActions doc (Range (Position 8 9) (Position 8 9)) - - liftIO $ length cas == 1 @? "Expected one code action, but got: " <> show cas - let ca = head cas - - liftIO $ (ca ^. L.title == "Add \"NamedFieldPuns\"") @? "NamedFieldPuns code action" - - executeCodeAction ca - - contents <- documentContents doc - - let expected = - [ "{-# LANGUAGE NamedFieldPuns #-}" - , "module NamedFieldPuns where" - , "" - , "data Record = Record" - , " { a :: Int," - , " b :: Double," - , " c :: String" - , " }" - , "" - , "f Record{a, b} = a" - ] - - liftIO $ T.lines contents @?= expected - ] - -disableWarningTests :: TestTree -disableWarningTests = - testGroup "disable warnings" $ - [ - ( "missing-signatures" - , T.unlines - [ "{-# OPTIONS_GHC -Wall #-}" - , "main = putStrLn \"hello\"" - ] - , T.unlines - [ "{-# OPTIONS_GHC -Wall #-}" - , "{-# OPTIONS_GHC -Wno-missing-signatures #-}" - , "main = putStrLn \"hello\"" - ] - ) - , - ( "unused-imports" - , T.unlines - [ "{-# OPTIONS_GHC -Wall #-}" - , "" - , "" - , "module M where" - , "" - , "import Data.Functor" - ] - , T.unlines - [ "{-# OPTIONS_GHC -Wall #-}" - , "" - , "" - , "{-# OPTIONS_GHC -Wno-unused-imports #-}" - , "module M where" - , "" - , "import Data.Functor" - ] - ) - ] - <&> \(warning, initialContent, expectedContent) -> testSession (T.unpack warning) $ do - doc <- createDoc "Module.hs" "haskell" initialContent - _ <- waitForDiagnostics - codeActs <- mapMaybe caResultToCodeAct <$> getCodeActions doc (Range (Position 0 0) (Position 0 0)) - case find (\CodeAction{_title} -> _title == "Disable \"" <> warning <> "\" warnings") codeActs of - Nothing -> liftIO $ assertFailure "No code action with expected title" - Just action -> do - executeCodeAction action - contentAfterAction <- documentContents doc - liftIO $ expectedContent @=? contentAfterAction - where - caResultToCodeAct = \case - InL _ -> Nothing - InR c -> Just c - -unusedTermTests :: TestTree -unusedTermTests = testGroup "unused term code actions" [ - ignoreTestBecause "no support for prefixing unused names with _" $ testCase "Prefixes with '_'" $ - runSession hlsCommand fullCaps "test/testdata/" $ do - doc <- openDoc "UnusedTerm.hs" "haskell" - - _ <- waitForDiagnosticsFromSource doc "typecheck" - cars <- getAllCodeActions doc - prefixImUnused <- liftIO $ inspectCodeAction cars ["Prefix imUnused with _"] - - executeCodeAction prefixImUnused - - edit <- skipManyTill anyMessage $ getDocumentEdit doc - - let expected = [ "{-# OPTIONS_GHC -Wall #-}" - , "module UnusedTerm () where" - , "_imUnused :: Int -> Int" - , "_imUnused 1 = 1" - , "_imUnused 2 = 2" - , "_imUnused _ = 3" - ] - - liftIO $ edit @?= T.unlines expected - - -- See https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#textDocument_codeAction - -- `CodeActionContext` - , testCase "respect 'only' parameter" $ runSession hlsCommand fullCaps "test/testdata" $ do - doc <- openDoc "CodeActionOnly.hs" "haskell" - _ <- waitForDiagnosticsFrom doc - diags <- getCurrentDiagnostics doc - let params = CodeActionParams Nothing Nothing doc (Range (Position 1 0) (Position 4 0)) caContext - caContext = CodeActionContext (List diags) (Just (List [CodeActionRefactorInline])) - caContextAllActions = CodeActionContext (List diags) Nothing - -- Verify that we get code actions of at least two different kinds. - ResponseMessage _ _ (Right (List allCodeActions)) - <- request STextDocumentCodeAction (params & L.context .~ caContextAllActions) - liftIO $ do - redundantId <- inspectCodeAction allCodeActions ["Redundant id"] - redundantId ^. L.kind @?= Just CodeActionQuickFix - unfoldFoo <- inspectCodeAction allCodeActions ["Unfold foo"] - unfoldFoo ^. L.kind @?= Just CodeActionRefactorInline - -- Verify that that when we set the only parameter, we only get actions - -- of the right kind. - ResponseMessage _ _ (Right (List res)) <- request STextDocumentCodeAction params - let cas = map fromAction res - kinds = map (^. L.kind) cas - liftIO $ do - not (null kinds) @? "We found an action of kind RefactorInline" - all (Just CodeActionRefactorInline ==) kinds @? "All CodeActionRefactorInline" - ] - -noLiteralCaps :: C.ClientCapabilities -noLiteralCaps = def { C._textDocument = Just textDocumentCaps } - where - textDocumentCaps = def { C._codeAction = Just codeActionCaps } - codeActionCaps = CodeActionClientCapabilities (Just True) Nothing Nothing - -testSession :: String -> Session () -> TestTree -testSession name s = testCase name $ withTempDir $ \dir -> - runSession hlsCommand fullCaps dir s +{-# LANGUAGE CPP #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}++module FunctionalCodeAction (tests) where++import Control.Lens hiding (List)+import Control.Monad+import Data.Aeson+import qualified Data.HashMap.Strict as HM+import Data.List+import Data.Maybe+import qualified Data.Text as T+import Ide.Plugin.Config+import Language.LSP.Test as Test+import qualified Language.LSP.Types.Capabilities as C+import qualified Language.LSP.Types.Lens as L+import Test.Hls+import Test.Hspec.Expectations++import System.FilePath ((</>))+import System.IO.Extra (withTempDir)+import Test.Hls.Command++{-# ANN module ("HLint: ignore Reduce duplication"::String) #-}++tests :: TestTree+tests = testGroup "code actions" [+ hlintTests+ , importTests+ , missingPragmaTests+ , disableWarningTests+ , packageTests+ , redundantImportTests+ , renameTests+ , signatureTests+ , typedHoleTests+ , unusedTermTests+ ]+++hlintTests :: TestTree+hlintTests = testGroup "hlint suggestions" [+ testCase "provides 3.8 code actions including apply all" $ runHlintSession "" $ do+ doc <- openDoc "ApplyRefact2.hs" "haskell"+ diags@(reduceDiag:_) <- waitForDiagnosticsFromSource doc "hlint"++ liftIO $ do+ length diags @?= 2 -- "Eta Reduce" and "Redundant Id"+ reduceDiag ^. L.range @?= Range (Position 1 0) (Position 1 12)+ reduceDiag ^. L.severity @?= Just DsInfo+ reduceDiag ^. L.code @?= Just (InR "refact:Eta reduce")+ reduceDiag ^. L.source @?= Just "hlint"++ cas <- map fromAction <$> getAllCodeActions doc++ let applyAll = find (\ca -> "Apply all hints" `T.isSuffixOf` (ca ^. L.title)) cas+ let redId = find (\ca -> "Redundant id" `T.isSuffixOf` (ca ^. L.title)) cas+ let redEta = find (\ca -> "Eta reduce" `T.isSuffixOf` (ca ^. L.title)) cas++ liftIO $ isJust applyAll @? "There is 'Apply all hints' code action"+ liftIO $ isJust redId @? "There is 'Redundant id' code action"+ liftIO $ isJust redEta @? "There is 'Eta reduce' code action"++ executeCodeAction (fromJust redId)++ contents <- skipManyTill anyMessage $ getDocumentEdit doc+ liftIO $ contents @?= "main = undefined\nfoo x = x\n"++ , testCase "falls back to pre 3.8 code actions" $ runSession hlsCommand noLiteralCaps "test/testdata/hlint" $ do+ doc <- openDoc "ApplyRefact2.hs" "haskell"++ _ <- waitForDiagnosticsFromSource doc "hlint"++ cars <- getAllCodeActions doc+ etaReduce <- liftIO $ inspectCommand cars ["Eta reduce"]++ executeCommand etaReduce++ contents <- skipManyTill anyMessage $ getDocumentEdit doc+ liftIO $ contents @?= "main = undefined\nfoo = id\n"++ , testCase "changing configuration enables or disables hlint diagnostics" $ runHlintSession "" $ do+ let config = def { hlintOn = True }+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config))++ doc <- openDoc "ApplyRefact2.hs" "haskell"+ testHlintDiagnostics doc++ let config' = def { hlintOn = False }+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config'))++ diags' <- waitForDiagnosticsFrom doc++ liftIO $ noHlintDiagnostics diags'++ , testCase "changing document contents updates hlint diagnostics" $ runHlintSession "" $ do+ doc <- openDoc "ApplyRefact2.hs" "haskell"+ testHlintDiagnostics doc++ let change = TextDocumentContentChangeEvent+ (Just (Range (Position 1 8) (Position 1 12)))+ Nothing "x"+ changeDoc doc [change]+ expectNoMoreDiagnostics 3 doc "hlint"++ let change' = TextDocumentContentChangeEvent+ (Just (Range (Position 1 8) (Position 1 12)))+ Nothing "id x"+ changeDoc doc [change']+ testHlintDiagnostics doc++ , knownBrokenForGhcVersions [GHC88, GHC86] "hlint doesn't take in account cpp flag as ghc -D argument" $+ testCase "hlint diagnostics works with CPP via ghc -XCPP argument (#554)" $ runHlintSession "cpp" $ do+ doc <- openDoc "ApplyRefact3.hs" "haskell"+ testHlintDiagnostics doc++ , knownBrokenForGhcVersions [GHC88, GHC86] "hlint doesn't take in account cpp flag as ghc -D argument" $+ testCase "hlint diagnostics works with CPP via language pragma (#554)" $ runHlintSession "" $ do+ doc <- openDoc "ApplyRefact3.hs" "haskell"+ testHlintDiagnostics doc++ , testCase "hlint diagnostics works with CPP via -XCPP argument and flag via #include header (#554)" $ runHlintSession "cpp" $ do+ doc <- openDoc "ApplyRefact2.hs" "haskell"+ testHlintDiagnostics doc++ , testCase "apply-refact works with -XLambdaCase argument (#590)" $ runHlintSession "lambdacase" $ do+ testRefactor "ApplyRefact1.hs" "Redundant bracket"+ expectedLambdaCase++ , testCase "apply-refact works with -XTypeApplications argument (#1242)" $ runHlintSession "typeapps" $ do+ testRefactor "ApplyRefact1.hs" "Redundant bracket"+ expectedTypeApp++ , testCase "apply hints works with LambdaCase via language pragma" $ runHlintSession "" $ do+ testRefactor "ApplyRefact1.hs" "Redundant bracket"+ ("{-# LANGUAGE LambdaCase #-}" : expectedLambdaCase)++ , expectFailBecause "apply-refact doesn't work with cpp" $+ testCase "apply hints works with CPP via -XCPP argument" $ runHlintSession "cpp" $ do+ testRefactor "ApplyRefact3.hs" "Redundant bracket"+ expectedCPP++ , expectFailBecause "apply-refact doesn't work with cpp" $+ testCase "apply hints works with CPP via language pragma" $ runHlintSession "" $ do+ testRefactor "ApplyRefact3.hs" "Redundant bracket"+ ("{-# LANGUAGE CPP #-}" : expectedCPP)++ , testCase "hlint diagnostics ignore hints honouring .hlint.yaml" $ runHlintSession "ignore" $ do+ doc <- openDoc "ApplyRefact.hs" "haskell"+ expectNoMoreDiagnostics 3 doc "hlint"++ , testCase "hlint diagnostics ignore hints honouring ANN annotations" $ runHlintSession "" $ do+ doc <- openDoc "ApplyRefact4.hs" "haskell"+ expectNoMoreDiagnostics 3 doc "hlint"++ , knownBrokenForGhcVersions [GHC810] "hlint plugin doesn't honour HLINT annotations (#838)" $+ testCase "hlint diagnostics ignore hints honouring HLINT annotations" $ runHlintSession "" $ do+ doc <- openDoc "ApplyRefact5.hs" "haskell"+ expectNoMoreDiagnostics 3 doc "hlint"++ , testCase "apply-refact preserve regular comments" $ runHlintSession "" $ do+ testRefactor "ApplyRefact6.hs" "Redundant bracket" expectedComments+ ]+ where+ runHlintSession :: FilePath -> Session a -> IO a+ runHlintSession subdir =+ failIfSessionTimeout . runSession hlsCommand fullCaps ("test/testdata/hlint" </> subdir)++ noHlintDiagnostics :: [Diagnostic] -> Assertion+ noHlintDiagnostics diags =+ Just "hlint" `notElem` map (^. L.source) diags @? "There are no hlint diagnostics"++ testHlintDiagnostics doc = do+ diags <- waitForDiagnosticsFromSource doc "hlint"+ liftIO $ length diags > 0 @? "There are hlint diagnostics"++ testRefactor file caTitle expected = do+ doc <- openDoc file "haskell"+ testHlintDiagnostics doc++ cas <- map fromAction <$> getAllCodeActions doc+ let ca = find (\ca -> caTitle `T.isSuffixOf` (ca ^. L.title)) cas+ liftIO $ isJust ca @? ("There is '" ++ T.unpack caTitle ++"' code action")++ executeCodeAction (fromJust ca)++ contents <- skipManyTill anyMessage $ getDocumentEdit doc+ liftIO $ contents @?= T.unlines expected++ expectedLambdaCase = [ "module ApplyRefact1 where", ""+ , "f = \\case \"true\" -> True"+ , " _ -> False"+ ]+ expectedCPP = [ "module ApplyRefact3 where", ""+ , "#ifdef FLAG"+ , "f = 1"+ , "#else"+ , "g = 2"+ , "#endif", ""+ ]+ expectedComments = [ "-- comment before header"+ , "module ApplyRefact6 where", ""+ , "{-# standalone annotation #-}", ""+ , "-- standalone comment", ""+ , "-- | haddock comment"+ , "f = {- inline comment -}{- inline comment inside refactored code -} 1 -- ending comment", ""+ , "-- final comment"+ ]+ expectedTypeApp = [ "module ApplyRefact1 where", ""+ , "a = id @Int 1"+ ]+renameTests :: TestTree+renameTests = testGroup "rename suggestions" [+ testCase "works" $ runSession hlsCommand noLiteralCaps "test/testdata" $ do+ doc <- openDoc "CodeActionRename.hs" "haskell"++ _ <- waitForDiagnosticsFromSource doc "typecheck"++ cars <- getAllCodeActions doc+ replaceButStrLn <- liftIO $ inspectCommand cars ["Replace with", "putStrLn"]+ executeCommand replaceButStrLn+ _ <- anyRequest++ x:_ <- T.lines <$> documentContents doc+ liftIO $ x @?= "main = putStrLn \"hello\""++ , testCase "doesn't give both documentChanges and changes"+ $ runSession hlsCommand noLiteralCaps "test/testdata" $ do+ doc <- openDoc "CodeActionRename.hs" "haskell"++ _ <- waitForDiagnosticsFromSource doc "typecheck"++ cars <- getAllCodeActions doc+ cmd <- liftIO $ inspectCommand cars ["Replace with", "putStrLn"]+ let Just (List [Object args]) = cmd ^. L.arguments+ Object editParams = args HM.! "fallbackWorkspaceEdit"+ liftIO $ do+ "changes" `HM.member` editParams @? "Contains changes"+ not ("documentChanges" `HM.member` editParams) @? "Doesn't contain documentChanges"++ executeCommand cmd+ _ <- anyRequest++ x1:x2:_ <- T.lines <$> documentContents doc+ liftIO $+ x1 == "main = putStrLn \"hello\""+ || x2 == "foo = putStrLn \"world\""+ @? "One of the typos got fixed"+ ]++importTests :: TestTree+importTests = testGroup "import suggestions" [+ testCase "works with 3.8 code action kinds" $ runSession hlsCommand fullCaps "test/testdata" $ do+ doc <- openDoc "CodeActionImport.hs" "haskell"+ -- No Formatting:+ let config = def { formattingProvider = "none" }+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config))++ (diag:_) <- waitForDiagnosticsFrom doc+ liftIO $ diag ^. L.message @?= "Variable not in scope: when :: Bool -> IO () -> IO ()"++ actionsOrCommands <- getAllCodeActions doc+ let actns = map fromAction actionsOrCommands++ importControlMonad <- liftIO $ inspectCodeAction actionsOrCommands ["import Control.Monad"]+ liftIO $ do+ expectCodeAction actionsOrCommands ["import Control.Monad (when)"]+ length actns >= 10 @? "There are some actions"++ executeCodeAction importControlMonad++ contents <- documentContents doc+ liftIO $ contents @?= "import Control.Monad\nmain :: IO ()\nmain = when True $ putStrLn \"hello\""+ ]++packageTests :: TestTree+packageTests = testGroup "add package suggestions" [+ ignoreTestBecause "no support for adding dependent packages via code action" $ testCase "adds to .cabal files" $ do+ flushStackEnvironment+ runSession hlsCommand fullCaps "test/testdata/addPackageTest/cabal-exe" $ do+ doc <- openDoc "AddPackage.hs" "haskell"++ -- ignore the first empty hlint diagnostic publish+ [_,diag:_] <- count 2 $ waitForDiagnosticsFrom doc++ let prefixes = [ "Could not load module `Data.Text'" -- Windows && GHC >= 8.6+ , "Could not find module `Data.Text'" -- Windows+ , "Could not load module ‘Data.Text’" -- GHC >= 8.6+ , "Could not find module ‘Data.Text’"+ ]+ in liftIO $ any (`T.isPrefixOf` (diag ^. L.message)) prefixes @? "Contains prefix"++ acts <- getAllCodeActions doc+ let (InR action:_) = acts++ liftIO $ do+ action ^. L.title @?= "Add text as a dependency"+ action ^. L.kind @?= Just CodeActionQuickFix+ "package:add" `T.isSuffixOf` (action ^. L.command . _Just . L.command) @? "Command contains package:add"++ executeCodeAction action++ contents <- skipManyTill anyMessage $ getDocumentEdit . TextDocumentIdentifier =<< getDocUri "add-package-test.cabal"+ liftIO $+ any (\l -> "text -any" `T.isSuffixOf` l || "text : {} -any" `T.isSuffixOf` l) (T.lines contents) @? "Contains text package"++ , ignoreTestBecause "no support for adding dependent packages via code action" $ testCase "adds to hpack package.yaml files" $+ runSession hlsCommand fullCaps "test/testdata/addPackageTest/hpack-exe" $ do+ doc <- openDoc "app/Asdf.hs" "haskell"++ -- ignore the first empty hlint diagnostic publish+ [_,_:diag:_] <- count 2 $ waitForDiagnosticsFrom doc++ let prefixes = [ "Could not load module `Codec.Compression.GZip'" -- Windows && GHC >= 8.6+ , "Could not find module `Codec.Compression.GZip'" -- Windows+ , "Could not load module ‘Codec.Compression.GZip’" -- GHC >= 8.6+ , "Could not find module ‘Codec.Compression.GZip’"+ ]+ in liftIO $ any (`T.isPrefixOf` (diag ^. L.message)) prefixes @? "Diagnostic contains message"++ mActions <- getAllCodeActions doc+ let allActions = map fromAction mActions+ action = head allActions++ liftIO $ do+ action ^. L.title @?= "Add zlib as a dependency"+ forM_ allActions $ \a -> a ^. L.kind @?= Just CodeActionQuickFix+ forM_ allActions $ \a -> "package:add" `T.isSuffixOf` (a ^. L.command . _Just . L.command) @? "Command contains package:add"++ executeCodeAction action++ contents <- skipManyTill anyMessage $ getDocumentEdit . TextDocumentIdentifier =<< getDocUri "package.yaml"+ liftIO $ do+ "zlib" `T.isSuffixOf` (T.lines contents !! 3) @? "Contains zlib"+ "zlib" `T.isSuffixOf` (T.lines contents !! 21) @? "Does not contain zlib in unrelated component"+ ]++redundantImportTests :: TestTree+redundantImportTests = testGroup "redundant import code actions" [+ testCase "remove solitary redundant imports" $+ runSession hlsCommand fullCaps "test/testdata/redundantImportTest/" $ do+ doc <- openDoc "src/CodeActionRedundant.hs" "haskell"++ diags <- waitForDiagnosticsFromSource doc "typecheck"+ liftIO $ expectDiagnostic diags ["The import of", "Data.List", "is redundant"]++ mActions <- getAllCodeActions doc++ let allActions = map fromAction mActions+ actionTitles = map (view L.title) allActions++ liftIO $ actionTitles `shouldContain` ["Remove import", "Remove all redundant imports"]++ let Just removeAction = find (\x -> x ^. L.title == "Remove import") allActions++ liftIO $ do+ forM_ allActions $ \a -> a ^. L.kind @?= Just CodeActionQuickFix+ forM_ allActions $ \a -> a ^. L.command @?= Nothing+ forM_ allActions $ \a -> isJust (a ^. L.edit) @? "Has edit"++ executeCodeAction removeAction++ -- No command/applyworkspaceedit should be here, since action+ -- provides workspace edit property which skips round trip to+ -- the server+ contents <- documentContents doc+ liftIO $ contents @?= "{-# OPTIONS_GHC -Wunused-imports #-}\nmodule CodeActionRedundant where\nmain :: IO ()\nmain = putStrLn \"hello\"\n"++ , testCase "doesn't touch other imports" $ runSession hlsCommand noLiteralCaps "test/testdata/redundantImportTest/" $ do+ doc <- openDoc "src/MultipleImports.hs" "haskell"+ _ <- waitForDiagnosticsFromSource doc "typecheck"+ cas <- getAllCodeActions doc+ cmd <- liftIO $ inspectCommand cas ["redundant import"]+ executeCommand cmd+ _ <- anyRequest+ contents <- documentContents doc+ liftIO $ T.lines contents @?=+ [ "{-# OPTIONS_GHC -Wunused-imports #-}"+ , "module MultipleImports where"+ , "import Data.Maybe"+ , "foo :: Int"+ , "foo = fromJust (Just 3)"+ ]+ ]++typedHoleTests :: TestTree+typedHoleTests = testGroup "typed hole code actions" [+ testCase "works" $+ runSession hlsCommand fullCaps "test/testdata" $ do+ doc <- openDoc "TypedHoles.hs" "haskell"+ _ <- waitForDiagnosticsFromSource doc "typecheck"+ cas <- getAllCodeActions doc+ liftIO $ do+ expectCodeAction cas ["replace _ with minBound"]+ expectCodeAction cas ["replace _ with foo _"]+ replaceWithMaxBound <- liftIO $ inspectCodeAction cas ["replace _ with maxBound"]++ executeCodeAction replaceWithMaxBound++ contents <- documentContents doc++ liftIO $ contents @?= T.concat+ [ "module TypedHoles where\n"+ , "foo :: [Int] -> Int\n"+ , "foo x = maxBound"+ ]++ , testCase "shows more suggestions" $+ runSession hlsCommand fullCaps "test/testdata" $ do+ doc <- openDoc "TypedHoles2.hs" "haskell"+ _ <- waitForDiagnosticsFromSource doc "typecheck"+ cas <- getAllCodeActions doc++ liftIO $ do+ expectCodeAction cas ["replace _ with foo2 _"]+ expectCodeAction cas ["replace _ with A _"]+ replaceWithStuff <- liftIO $ inspectCodeAction cas ["replace _ with stuff _"]++ executeCodeAction replaceWithStuff++ contents <- documentContents doc++ liftIO $ T.lines contents @?=+ [ "module TypedHoles2 (foo2) where"+ , "newtype A = A Int"+ , "foo2 :: [A] -> A"+ , "foo2 x = (stuff _)"+ , " where"+ , " stuff (A a) = A (a + 1)"+ ]+ ]++signatureTests :: TestTree+signatureTests = testGroup "missing top level signature code actions" [+ testCase "Adds top level signature" $+ runSession hlsCommand fullCaps "test/testdata/" $ do+ doc <- openDoc "TopLevelSignature.hs" "haskell"++ _ <- waitForDiagnosticsFromSource doc "typecheck"+ cas <- getAllCodeActions doc++ liftIO $ expectCodeAction cas ["add signature: main :: IO ()"]++ replaceWithStuff <- liftIO $ inspectCodeAction cas ["add signature"]+ executeCodeAction replaceWithStuff++ contents <- documentContents doc++ let expected = [ "{-# OPTIONS_GHC -Wall #-}"+ , "module TopLevelSignature where"+ , "main :: IO ()"+ , "main = do"+ , " putStrLn \"Hello\""+ , " return ()"+ ]++ liftIO $ T.lines contents @?= expected+ ]++missingPragmaTests :: TestTree+missingPragmaTests = testGroup "missing pragma warning code actions" [+ testCase "Adds TypeSynonymInstances pragma" $ do+ runSession hlsCommand fullCaps "test/testdata/addPragmas" $ do+ doc <- openDoc "NeedsPragmas.hs" "haskell"++ _ <- waitForDiagnosticsFromSource doc "typecheck"+ cas <- map fromAction <$> getAllCodeActions doc++ liftIO $ "Add \"TypeSynonymInstances\"" `elem` map (^. L.title) cas @? "Contains TypeSynonymInstances code action"+ liftIO $ "Add \"FlexibleInstances\"" `elem` map (^. L.title) cas @? "Contains FlexibleInstances code action"++ executeCodeAction $ head cas++ contents <- documentContents doc++ let expected = [ "{-# LANGUAGE TypeSynonymInstances #-}"+ , "module NeedsPragmas where"+ , ""+ , "import GHC.Generics"+ , ""+ , "main = putStrLn \"hello\""+ , ""+ , "type Foo = Int"+ , ""+ , "instance Show Foo where"+ , " show x = undefined"+ , ""+ , "instance Show (Int,String) where"+ , " show = undefined"+ , ""+ , "data FFF a = FFF Int String a"+ , " deriving (Generic,Functor,Traversable)"+ ]++ liftIO $ T.lines contents @?= expected++ , testCase "Adds TypeApplications pragma" $ do+ runSession hlsCommand fullCaps "test/testdata/addPragmas" $ do+ doc <- openDoc "TypeApplications.hs" "haskell"++ _ <- waitForDiagnosticsFrom doc+ cas <- map fromAction <$> getAllCodeActions doc++ liftIO $ "Add \"TypeApplications\"" `elem` map (^. L.title) cas @? "Contains TypeApplications code action"++ executeCodeAction $ head cas++ contents <- documentContents doc++ let expected =+-- TODO: Why CPP???+#if __GLASGOW_HASKELL__ < 810+ [ "{-# LANGUAGE ScopedTypeVariables #-}"+ , "{-# LANGUAGE TypeApplications #-}"+#else+ [ "{-# LANGUAGE TypeApplications #-}"+ , "{-# LANGUAGE ScopedTypeVariables #-}"+#endif+ , "module TypeApplications where"+ , ""+ , "foo :: forall a. a -> a"+ , "foo = id @a"+ ]++ liftIO $ T.lines contents @?= expected+ , testCase "No duplication" $ do+ runSession hlsCommand fullCaps "test/testdata/addPragmas" $ do+ doc <- openDoc "NamedFieldPuns.hs" "haskell"++ _ <- waitForDiagnosticsFrom doc+ cas <- map fromAction <$> getCodeActions doc (Range (Position 8 9) (Position 8 9))++ liftIO $ length cas == 1 @? "Expected one code action, but got: " <> show cas+ let ca = head cas++ liftIO $ (ca ^. L.title == "Add \"NamedFieldPuns\"") @? "NamedFieldPuns code action"++ executeCodeAction ca++ contents <- documentContents doc++ let expected =+ [ "{-# LANGUAGE NamedFieldPuns #-}"+ , "module NamedFieldPuns where"+ , ""+ , "data Record = Record"+ , " { a :: Int,"+ , " b :: Double,"+ , " c :: String"+ , " }"+ , ""+ , "f Record{a, b} = a"+ ]+ liftIO $ T.lines contents @?= expected+ , testCase "After Shebang" $ do+ runSession hlsCommand fullCaps "test/testdata/addPragmas" $ do+ doc <- openDoc "AfterShebang.hs" "haskell"++ _ <- waitForDiagnosticsFrom doc+ cas <- map fromAction <$> getAllCodeActions doc++ liftIO $ "Add \"NamedFieldPuns\"" `elem` map (^. L.title) cas @? "Contains NamedFieldPuns code action"++ executeCodeAction $ head cas++ contents <- documentContents doc++ let expected =+ [ "#! /usr/bin/env nix-shell"+ , "#! nix-shell --pure -i runghc -p \"haskellPackages.ghcWithPackages (hp: with hp; [ turtle ])\""+ , ""+ , "{-# LANGUAGE NamedFieldPuns #-}"+ , "module AfterShebang where"+ , ""+ , "data Record = Record"+ , " { a :: Int,"+ , " b :: Double,"+ , " c :: String"+ , " }"+ , ""+ , "f Record{a, b} = a"+ ]++ liftIO $ T.lines contents @?= expected+ ]++disableWarningTests :: TestTree+disableWarningTests =+ testGroup "disable warnings" $+ [+ ( "missing-signatures"+ , T.unlines+ [ "{-# OPTIONS_GHC -Wall #-}"+ , "main = putStrLn \"hello\""+ ]+ , T.unlines+ [ "{-# OPTIONS_GHC -Wall #-}"+ , "{-# OPTIONS_GHC -Wno-missing-signatures #-}"+ , "main = putStrLn \"hello\""+ ]+ )+ ,+ ( "unused-imports"+ , T.unlines+ [ "{-# OPTIONS_GHC -Wall #-}"+ , ""+ , ""+ , "module M where"+ , ""+ , "import Data.Functor"+ ]+ , T.unlines+ [ "{-# OPTIONS_GHC -Wall #-}"+ , ""+ , ""+ , "{-# OPTIONS_GHC -Wno-unused-imports #-}"+ , "module M where"+ , ""+ , "import Data.Functor"+ ]+ )+ ]+ <&> \(warning, initialContent, expectedContent) -> testSession (T.unpack warning) $ do+ doc <- createDoc "Module.hs" "haskell" initialContent+ _ <- waitForDiagnostics+ codeActs <- mapMaybe caResultToCodeAct <$> getAllCodeActions doc+ case find (\CodeAction{_title} -> _title == "Disable \"" <> warning <> "\" warnings") codeActs of+ Nothing -> liftIO $ assertFailure "No code action with expected title"+ Just action -> do+ executeCodeAction action+ contentAfterAction <- documentContents doc+ liftIO $ expectedContent @=? contentAfterAction+ where+ caResultToCodeAct = \case+ InL _ -> Nothing+ InR c -> Just c++unusedTermTests :: TestTree+unusedTermTests = testGroup "unused term code actions" [+ ignoreTestBecause "no support for prefixing unused names with _" $ testCase "Prefixes with '_'" $+ runSession hlsCommand fullCaps "test/testdata/" $ do+ doc <- openDoc "UnusedTerm.hs" "haskell"++ _ <- waitForDiagnosticsFromSource doc "typecheck"+ cars <- getAllCodeActions doc+ prefixImUnused <- liftIO $ inspectCodeAction cars ["Prefix imUnused with _"]++ executeCodeAction prefixImUnused++ edit <- skipManyTill anyMessage $ getDocumentEdit doc++ let expected = [ "{-# OPTIONS_GHC -Wall #-}"+ , "module UnusedTerm () where"+ , "_imUnused :: Int -> Int"+ , "_imUnused 1 = 1"+ , "_imUnused 2 = 2"+ , "_imUnused _ = 3"+ ]++ liftIO $ edit @?= T.unlines expected++ -- See https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#textDocument_codeAction+ -- `CodeActionContext`+ , testCase "respect 'only' parameter" $ runSession hlsCommand fullCaps "test/testdata" $ do+ doc <- openDoc "CodeActionOnly.hs" "haskell"+ _ <- waitForDiagnosticsFrom doc+ diags <- getCurrentDiagnostics doc+ let params = CodeActionParams Nothing Nothing doc (Range (Position 1 0) (Position 4 0)) caContext+ caContext = CodeActionContext (List diags) (Just (List [CodeActionRefactorInline]))+ caContextAllActions = CodeActionContext (List diags) Nothing+ -- Verify that we get code actions of at least two different kinds.+ ResponseMessage _ _ (Right (List allCodeActions))+ <- request STextDocumentCodeAction (params & L.context .~ caContextAllActions)+ liftIO $ do+ redundantId <- inspectCodeAction allCodeActions ["Redundant id"]+ redundantId ^. L.kind @?= Just CodeActionQuickFix+ unfoldFoo <- inspectCodeAction allCodeActions ["Unfold foo"]+ unfoldFoo ^. L.kind @?= Just CodeActionRefactorInline+ -- Verify that that when we set the only parameter, we only get actions+ -- of the right kind.+ ResponseMessage _ _ (Right (List res)) <- request STextDocumentCodeAction params+ let cas = map fromAction res+ kinds = map (^. L.kind) cas+ liftIO $ do+ not (null kinds) @? "We found an action of kind RefactorInline"+ all (Just CodeActionRefactorInline ==) kinds @? "All CodeActionRefactorInline"+ ]++noLiteralCaps :: C.ClientCapabilities+noLiteralCaps = def { C._textDocument = Just textDocumentCaps }+ where+ textDocumentCaps = def { C._codeAction = Just codeActionCaps }+ codeActionCaps = CodeActionClientCapabilities (Just True) Nothing Nothing Nothing Nothing Nothing Nothing++testSession :: String -> Session () -> TestTree+testSession name s = testCase name $ withTempDir $ \dir ->+ runSession hlsCommand fullCaps dir s
@@ -1,37 +1,31 @@-{-# LANGUAGE OverloadedStrings #-} - -module FunctionalLiquid (tests) where - -import Control.Lens hiding (List) -import Control.Monad.IO.Class -import Data.Aeson -import Data.Default -import Language.LSP.Test hiding (message) -import Language.LSP.Types as LSP -import Language.LSP.Types.Lens as LSP hiding (contents) -import Ide.Plugin.Config -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.ExpectedFailure (ignoreTestBecause) -import Test.Tasty.HUnit - --- --------------------------------------------------------------------- - -tests :: TestTree -tests = testGroup "liquid haskell diagnostics" [ - ignoreTestBecause "no liquid haskell" - $ testCase "liquid haskell generates diagnostics" $ - runSession hlsCommand codeActionSupportCaps "test/testdata" $ do - doc <- openDoc "liquid/Evens.hs" "haskell" - - let config = def { liquidOn = True, hlintOn = False } - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config)) - - diags <- waitForDiagnosticsFromSource doc "liquid" - d <- liftIO $ inspectDiagnostic diags ["Liquid Type Mismatch"] - liftIO $ do - length diags @?= 1 - d ^. range @?= Range (Position 8 0) (Position 8 11) - d ^. severity @?= Just DsError - d ^. code @?= Nothing - ] +{-# LANGUAGE OverloadedStrings #-}++module FunctionalLiquid (tests) where++import Control.Lens hiding (List)+import Data.Aeson+import Ide.Plugin.Config+import Language.LSP.Types.Lens as LSP hiding (contents)+import Test.Hls+import Test.Hls.Command++-- ---------------------------------------------------------------------++tests :: TestTree+tests = testGroup "liquid haskell diagnostics" [+ ignoreTestBecause "no liquid haskell"+ $ testCase "liquid haskell generates diagnostics" $+ runSession hlsCommand codeActionSupportCaps "test/testdata" $ do+ doc <- openDoc "liquid/Evens.hs" "haskell"++ let config = def { liquidOn = True, hlintOn = False }+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config))++ diags <- waitForDiagnosticsFromSource doc "liquid"+ d <- liftIO $ inspectDiagnostic diags ["Liquid Type Mismatch"]+ liftIO $ do+ length diags @?= 1+ d ^. range @?= Range (Position 8 0) (Position 8 11)+ d ^. severity @?= Just DsError+ d ^. code @?= Nothing+ ]
@@ -1,79 +0,0 @@-{-# LANGUAGE DisambiguateRecordFields #-} -{-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ViewPatterns #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE TypeOperators #-} -{-# LANGUAGE GADTs #-} - -module HaddockComments - ( tests, - ) -where - -import Control.Monad.IO.Class (liftIO) -import qualified Data.ByteString.Lazy as LBS -import Data.Foldable (find) -import Data.Maybe (mapMaybe) -import Data.Text (Text) -import Data.Text.Encoding (encodeUtf8) -import Language.LSP.Test -import Language.LSP.Types -import System.FilePath ((<.>), (</>)) -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.Golden -import Test.Tasty.HUnit - -tests :: TestTree -tests = - testGroup - "haddock comments" - [ goldenTest "HigherRankFunction" Signature 4 6, - goldenTest "KindSigFunction" Signature 9 10, - goldenTest "MultivariateFunction" Signature 4 8, - goldenTest "QualFunction" Signature 2 10, - goldenTest "Record" Record 7 2, - expectedNothing "ConstFunction" Signature 2 2, - expectedNothing "StaleFunction" Signature 3 3, - expectedNothing "StaleRecord" Record 3 12 - ] - -goldenTest :: FilePath -> GenCommentsType -> Int -> Int -> TestTree -goldenTest fp (toTitle -> expectedTitle) l c = goldenVsStringDiff (fp <> " (golden)") goldenGitDiff goldenFilePath $ - runSession hlsCommand fullCaps haddockCommentsPath $ do - doc <- openDoc hsFilePath "haskell" - _ <- waitForDiagnostics - actions <- getCodeActions doc (Range (Position l c) (Position l $ succ c)) - case find ((== Just expectedTitle) . caTitle) actions of - Just (InR x) -> do - executeCodeAction x - LBS.fromStrict . encodeUtf8 <$> documentContents doc - _ -> liftIO $ assertFailure "Unable to find CodeAction" - where - hsFilePath = fp <.> "hs" - goldenFilePath = haddockCommentsPath </> fp <.> "expected" <.> "hs" - -expectedNothing :: FilePath -> GenCommentsType -> Int -> Int -> TestTree -expectedNothing fp (toTitle -> expectedTitle) l c = testCase fp $ - runSession hlsCommand fullCaps haddockCommentsPath $ do - doc <- openDoc (fp <.> "hs") "haskell" - _ <- waitForDiagnostics - titles <- mapMaybe caTitle <$> getCodeActions doc (Range (Position l c) (Position l $ succ c)) - liftIO $ expectedTitle `notElem` titles @? "Unexpected CodeAction" - -data GenCommentsType = Signature | Record - -toTitle :: GenCommentsType -> Text -toTitle Signature = "Generate signature comments" -toTitle Record = "Generate fields comments" - -caTitle :: (Command |? CodeAction) -> Maybe Text -caTitle (InR CodeAction {_title}) = Just _title -caTitle _ = Nothing - -haddockCommentsPath :: String -haddockCommentsPath = "test" </> "testdata" </> "haddockComments" - -goldenGitDiff :: FilePath -> FilePath -> [String] -goldenGitDiff fRef fNew = ["git", "diff", "--no-index", "--text", "--exit-code", fRef, fNew]
@@ -1,35 +1,33 @@-{-# LANGUAGE OverloadedStrings #-} -module HieBios (tests) where - -import Control.Lens ((^.)) -import Control.Monad.IO.Class -import qualified Data.Text as T -import Language.LSP.Test -import Language.LSP.Types -import qualified Language.LSP.Types.Lens as L -import System.FilePath ((</>)) -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.HUnit - -tests :: TestTree -tests = testGroup "hie-bios" [ - testCase "loads modules inside main-is" $ do - writeFile (hieBiosErrorPath </> "hie.yaml") "" - runSession hlsCommand fullCaps "test/testdata/hieBiosMainIs" $ do - doc <- openDoc "Main.hs" "haskell" - Just mainHoverText <- getHover doc (Position 3 1) - let (HoverContents (MarkupContent _ x)) = mainHoverText ^. L.contents - liftIO $ "main :: IO ()" `T.isInfixOf` x - @? "found hover text for main" - - , testCase "reports errors in hie.yaml" $ do - writeFile (hieBiosErrorPath </> "hie.yaml") "" - runSession hlsCommand fullCaps hieBiosErrorPath $ do - _ <- openDoc "Foo.hs" "haskell" - (diag:_) <- waitForDiagnostics - liftIO $ "Expected a cradle: key containing the preferences" `T.isInfixOf` (diag ^. L.message) - @? "Error reported" - ] - where - hieBiosErrorPath = "test/testdata/hieBiosError" +{-# LANGUAGE OverloadedStrings #-}+module HieBios (tests) where++import Control.Lens ((^.))+import Control.Monad.IO.Class+import qualified Data.Text as T+import qualified Language.LSP.Types.Lens as L+import System.FilePath ((</>))+import Test.Hls+import Test.Hls.Command+++tests :: TestTree+tests = testGroup "hie-bios" [+ testCase "loads modules inside main-is" $ do+ writeFile (hieBiosErrorPath </> "hie.yaml") ""+ runSession hlsCommand fullCaps "test/testdata/hieBiosMainIs" $ do+ doc <- openDoc "Main.hs" "haskell"+ Just mainHoverText <- getHover doc (Position 3 1)+ let (HoverContents (MarkupContent _ x)) = mainHoverText ^. L.contents+ liftIO $ "main :: IO ()" `T.isInfixOf` x+ @? "found hover text for main"++ , testCase "reports errors in hie.yaml" $ do+ writeFile (hieBiosErrorPath </> "hie.yaml") ""+ runSession hlsCommand fullCaps hieBiosErrorPath $ do+ _ <- openDoc "Foo.hs" "haskell"+ (diag:_) <- waitForDiagnostics+ liftIO $ "Expected a cradle: key containing the preferences" `T.isInfixOf` (diag ^. L.message)+ @? "Error reported"+ ]+ where+ hieBiosErrorPath = "test/testdata/hieBiosError"
@@ -1,26 +1,22 @@-{-# LANGUAGE OverloadedStrings #-} -module Highlight (tests) where - -import Control.Monad.IO.Class -import Language.LSP.Test -import Language.LSP.Types -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.HUnit - -tests :: TestTree -tests = testGroup "highlight" [ - testCase "works" $ runSession (hlsCommand ++ " --test") fullCaps "test/testdata" $ do - doc <- openDoc "Highlight.hs" "haskell" - _ <- waitForDiagnosticsFrom doc - highlights <- getHighlights doc (Position 2 2) - liftIO $ do - let hls = - [ DocumentHighlight (mkRange 2 0 2 3) (Just HkWrite) - , DocumentHighlight (mkRange 4 22 4 25) (Just HkRead) - , DocumentHighlight (mkRange 3 6 3 9) (Just HkRead) - , DocumentHighlight (mkRange 1 0 1 3) (Just HkRead)] - mapM_ (\x -> x `elem` highlights @? "Contains highlight") hls - ] - where - mkRange sl sc el ec = Range (Position sl sc) (Position el ec) +{-# LANGUAGE OverloadedStrings #-}+module Highlight (tests) where++import Test.Hls+import Test.Hls.Command++tests :: TestTree+tests = testGroup "highlight" [+ testCase "works" $ runSession (hlsCommand ++ " --test") fullCaps "test/testdata" $ do+ doc <- openDoc "Highlight.hs" "haskell"+ _ <- waitForDiagnosticsFrom doc+ highlights <- getHighlights doc (Position 2 2)+ liftIO $ do+ let hls =+ [ DocumentHighlight (mkRange 2 0 2 3) (Just HkWrite)+ , DocumentHighlight (mkRange 4 22 4 25) (Just HkRead)+ , DocumentHighlight (mkRange 3 6 3 9) (Just HkRead)+ , DocumentHighlight (mkRange 1 0 1 3) (Just HkRead)]+ mapM_ (\x -> x `elem` highlights @? "Contains highlight") hls+ ]+ where+ mkRange sl sc el ec = Range (Position sl sc) (Position el ec)
@@ -1,63 +1,45 @@-module Main where - -import Class -import Command -import Completion -import Config -import Deferred -import Definition -import Diagnostic -import Eval -import Format -import FunctionalBadProject -import FunctionalCodeAction -import FunctionalLiquid -import HaddockComments -import HieBios -import Highlight -import ModuleName -import Progress -import Reference -import Rename -import Symbol -import Splice -import Test.Tasty -import Test.Tasty.Ingredients.Rerun -import Test.Tasty.Runners ( - consoleTestReporter, - listingTests, - ) -import Test.Tasty.Runners.AntXML -import TypeDefinition - -main :: IO () -main = - -- ingredient: xml runner writes json file of test results (https://github.com/ocharles/tasty-ant-xml/blob/master/Test/Tasty/Runners/AntXML.hs) - -- rerunningTests allow rerun of failed tests (https://github.com/ocharles/tasty-rerun/blob/master/src/Test/Tasty/Ingredients/Rerun.hs) - defaultMainWithIngredients - [antXMLRunner, rerunningTests [listingTests, consoleTestReporter]] - $ testGroup - "haskell-language-server" - [ Class.tests - , Command.tests - , Completion.tests - , Config.tests - , Deferred.tests - , Definition.tests - , Diagnostic.tests - , Eval.tests - , Format.tests - , FunctionalBadProject.tests - , FunctionalCodeAction.tests - , FunctionalLiquid.tests - , HieBios.tests - , Highlight.tests - , ModuleName.tests - , Progress.tests - , Reference.tests - , Rename.tests - , Symbol.tests - , TypeDefinition.tests - , Splice.tests - , HaddockComments.tests - ] +module Main where++import Command+import Completion+import Config+import Deferred+import Definition+import Diagnostic+import Format+import FunctionalBadProject+import FunctionalCodeAction+import FunctionalLiquid+import HieBios+import Highlight+import ModuleName+import Progress+import Reference+import Rename+import Symbol+import Test.Hls+import TypeDefinition++main :: IO ()+main = defaultTestRunner+ $ testGroup+ "haskell-language-server"+ [ Command.tests+ , Completion.tests+ , Config.tests+ , Deferred.tests+ , Definition.tests+ , Diagnostic.tests+ , Format.tests+ , FunctionalBadProject.tests+ , FunctionalCodeAction.tests+ , FunctionalLiquid.tests+ , HieBios.tests+ , Highlight.tests+ , ModuleName.tests+ , Progress.tests+ , Reference.tests+ , Rename.tests+ , Symbol.tests+ , TypeDefinition.tests+ ]
@@ -1,44 +1,36 @@-{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE DuplicateRecordFields #-} - -module ModuleName - ( tests - ) -where - -import Control.Applicative.Combinators (skipManyTill) -import Control.Monad.IO.Class (MonadIO (liftIO)) -import qualified Data.Text.IO as T -import Language.LSP.Test (anyMessage, documentContents, - executeCommand, fullCaps, - getCodeLenses, message, - openDoc, runSession) -import Language.LSP.Types -import System.FilePath ((<.>), (</>)) -import Test.Hls.Util (hlsCommand) -import Test.Tasty (TestTree, testGroup) -import Test.Tasty.HUnit (testCase, (@?=)) - -tests :: TestTree -tests = testGroup - "moduleName" - [ testCase "Add module header to empty module" $ goldenTest "TEmptyModule.hs" - , testCase "Fix wrong module name" $ goldenTest "TWrongModuleName.hs" - , testCase "Must infer module name as Main, if the file name starts with a lowercase" $ goldenTest "mainlike.hs" - ] - -goldenTest :: FilePath -> IO () -goldenTest input = runSession hlsCommand fullCaps testdataPath $ do - doc <- openDoc input "haskell" - -- getCodeLenses doc >>= liftIO . print . length - [CodeLens { _command = Just c }] <- getCodeLenses doc - executeCommand c - _resp <- skipManyTill anyMessage (message SWorkspaceApplyEdit) - edited <- documentContents doc - -- liftIO $ T.writeFile (testdataPath </> input <.> "expected") edited - expected <- liftIO $ T.readFile $ testdataPath </> input <.> "expected" - liftIO $ edited @?= expected - -testdataPath :: FilePath -testdataPath = "test/testdata/moduleName" +{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++module ModuleName+ ( tests+ )+where++import qualified Data.Text.IO as T+import System.FilePath ((<.>), (</>))+import Test.Hls+import Test.Hls.Command++tests :: TestTree+tests = testGroup+ "moduleName"+ [ testCase "Add module header to empty module" $ goldenTest "TEmptyModule.hs"+ , testCase "Fix wrong module name" $ goldenTest "TWrongModuleName.hs"+ , testCase "Must infer module name as Main, if the file name starts with a lowercase" $ goldenTest "mainlike.hs"+ ]++goldenTest :: FilePath -> IO ()+goldenTest input = runSession hlsCommand fullCaps testdataPath $ do+ doc <- openDoc input "haskell"+ -- getCodeLenses doc >>= liftIO . print . length+ [CodeLens { _command = Just c }] <- getCodeLenses doc+ executeCommand c+ _resp <- skipManyTill anyMessage (message SWorkspaceApplyEdit)+ edited <- documentContents doc+ -- liftIO $ T.writeFile (testdataPath </> input <.> "expected") edited+ expected <- liftIO $ T.readFile $ testdataPath </> input <.> "expected"+ liftIO $ edited @?= expected++testdataPath :: FilePath+testdataPath = "test/testdata/moduleName"
@@ -1,120 +1,113 @@-{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE DuplicateRecordFields #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE GADTs #-} - -module Progress (tests) where - -import Control.Applicative.Combinators -import Control.Lens hiding ((.=)) -import Control.Monad.IO.Class -import Data.Aeson (Value, decode, encode, object, toJSON, (.=)) -import Data.Default -import Data.List (delete) -import Data.Maybe (fromJust) -import Data.Text (Text, pack) -import Ide.Plugin.Config -import Language.LSP.Test -import Language.LSP.Types -import Language.LSP.Types.Capabilities -import qualified Language.LSP.Types.Lens as L -import System.FilePath ((</>)) -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.ExpectedFailure (ignoreTestBecause) -import Test.Tasty.HUnit - -tests :: TestTree -tests = - testGroup - "window/workDoneProgress" - [ testCase "sends indefinite progress notifications" $ - runSession hlsCommand progressCaps "test/testdata" $ do - let path = "hlint" </> "ApplyRefact2.hs" - _ <- openDoc path "haskell" - expectProgressReports [pack ("Setting up hlint (for " ++ path ++ ")"), "Processing"] - , testCase "eval plugin sends progress reports" $ - runSession hlsCommand progressCaps "plugins/hls-eval-plugin/test/testdata" $ do - doc <- openDoc "T1.hs" "haskell" - expectProgressReports ["Setting up testdata (for T1.hs)", "Processing"] - [evalLens] <- getCodeLenses doc - let cmd = evalLens ^?! L.command . _Just - _ <- sendRequest SWorkspaceExecuteCommand $ ExecuteCommandParams Nothing (cmd ^. L.command) (decode $ encode $ fromJust $ cmd ^. L.arguments) - expectProgressReports ["Evaluating"] - , testCase "ormolu plugin sends progress notifications" $ do - runSession hlsCommand progressCaps "test/testdata/format" $ do - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "ormolu")) - doc <- openDoc "Format.hs" "haskell" - expectProgressReports ["Setting up testdata (for Format.hs)", "Processing"] - _ <- sendRequest STextDocumentFormatting $ DocumentFormattingParams Nothing doc (FormattingOptions 2 True Nothing Nothing Nothing) - expectProgressReports ["Formatting Format.hs"] - , testCase "fourmolu plugin sends progress notifications" $ do - runSession hlsCommand progressCaps "test/testdata/format" $ do - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "fourmolu")) - doc <- openDoc "Format.hs" "haskell" - expectProgressReports ["Setting up testdata (for Format.hs)", "Processing"] - _ <- sendRequest STextDocumentFormatting $ DocumentFormattingParams Nothing doc (FormattingOptions 2 True Nothing Nothing Nothing) - expectProgressReports ["Formatting Format.hs"] - , ignoreTestBecause "no liquid Haskell support" $ - testCase "liquid haskell plugin sends progress notifications" $ do - runSession hlsCommand progressCaps "test/testdata" $ do - doc <- openDoc "liquid/Evens.hs" "haskell" - let config = def{liquidOn = True, hlintOn = False} - sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config)) - sendNotification STextDocumentDidSave (DidSaveTextDocumentParams doc Nothing) - expectProgressReports ["Running Liquid Haskell on Evens.hs"] - ] - -formatLspConfig :: Value -> Value -formatLspConfig provider = object ["haskell" .= object ["formattingProvider" .= (provider :: Value)]] - -progressCaps :: ClientCapabilities -progressCaps = fullCaps{_window = Just (WindowClientCapabilities (Just True))} - -data CollectedProgressNotification - = CreateM WorkDoneProgressCreateParams - | BeginM (ProgressParams WorkDoneProgressBeginParams) - | ProgressM (ProgressParams WorkDoneProgressReportParams) - | EndM (ProgressParams WorkDoneProgressEndParams) - -{- | Test that the server is correctly producing a sequence of progress related - messages. Each create must be pair with a corresponding begin and end, - optionally with some progress in between. Tokens must match. The begin - messages have titles describing the work that is in-progress, we check that - the titles we see are those we expect. --} -expectProgressReports :: [Text] -> Session () -expectProgressReports xs = expectProgressReports' [] xs - where - expectProgressReports' [] [] = return () - expectProgressReports' tokens expectedTitles = - do - skipManyTill anyMessage (create <|> begin <|> progress <|> end) - >>= \case - CreateM msg -> - expectProgressReports' (token msg : tokens) expectedTitles - BeginM msg -> do - liftIO $ title msg `expectElem` ("Indexing references from:":xs) - liftIO $ token msg `expectElem` tokens - expectProgressReports' tokens (delete (title msg) expectedTitles) - ProgressM msg -> do - liftIO $ token msg `expectElem` tokens - expectProgressReports' tokens expectedTitles - EndM msg -> do - liftIO $ token msg `expectElem` tokens - expectProgressReports' (delete (token msg) tokens) expectedTitles - title msg = msg ^. L.value . L.title - token msg = msg ^. L.token - create = CreateM . view L.params <$> message SWindowWorkDoneProgressCreate - begin = BeginM <$> satisfyMaybe (\case - FromServerMess SProgress (NotificationMessage _ _ (ProgressParams t (Begin x))) -> Just (ProgressParams t x) - _ -> Nothing) - progress = ProgressM <$> satisfyMaybe (\case - FromServerMess SProgress (NotificationMessage _ _ (ProgressParams t (Report x))) -> Just (ProgressParams t x) - _ -> Nothing) - end = EndM <$> satisfyMaybe (\case - FromServerMess SProgress (NotificationMessage _ _ (ProgressParams t (End x))) -> Just (ProgressParams t x) - _ -> Nothing) - expectElem a as = a `elem` as @? "Unexpected " ++ show a +{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Progress (tests) where++import Control.Lens hiding ((.=))+import Data.Aeson (Value, decode, encode, object,+ toJSON, (.=))+import Data.List (delete)+import Data.Maybe (fromJust)+import Data.Text (Text, pack)+import Ide.Plugin.Config+import Language.LSP.Types.Capabilities+import qualified Language.LSP.Types.Lens as L+import System.FilePath ((</>))+import Test.Hls+import Test.Hls.Command++tests :: TestTree+tests =+ testGroup+ "window/workDoneProgress"+ [ testCase "sends indefinite progress notifications" $+ runSession hlsCommand progressCaps "test/testdata" $ do+ let path = "hlint" </> "ApplyRefact2.hs"+ _ <- openDoc path "haskell"+ expectProgressReports [pack ("Setting up hlint (for " ++ path ++ ")"), "Processing", "Indexing"]+ , testCase "eval plugin sends progress reports" $+ runSession hlsCommand progressCaps "plugins/hls-eval-plugin/test/testdata" $ do+ doc <- openDoc "T1.hs" "haskell"+ expectProgressReports ["Setting up testdata (for T1.hs)", "Processing", "Indexing"]+ [evalLens] <- getCodeLenses doc+ let cmd = evalLens ^?! L.command . _Just+ _ <- sendRequest SWorkspaceExecuteCommand $ ExecuteCommandParams Nothing (cmd ^. L.command) (decode $ encode $ fromJust $ cmd ^. L.arguments)+ expectProgressReports ["Evaluating"]+ , testCase "ormolu plugin sends progress notifications" $ do+ runSession hlsCommand progressCaps "test/testdata/format" $ do+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "ormolu"))+ doc <- openDoc "Format.hs" "haskell"+ expectProgressReports ["Setting up testdata (for Format.hs)", "Processing", "Indexing"]+ _ <- sendRequest STextDocumentFormatting $ DocumentFormattingParams Nothing doc (FormattingOptions 2 True Nothing Nothing Nothing)+ expectProgressReports ["Formatting Format.hs"]+ , testCase "fourmolu plugin sends progress notifications" $ do+ runSession hlsCommand progressCaps "test/testdata/format" $ do+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "fourmolu"))+ doc <- openDoc "Format.hs" "haskell"+ expectProgressReports ["Setting up testdata (for Format.hs)", "Processing", "Indexing"]+ _ <- sendRequest STextDocumentFormatting $ DocumentFormattingParams Nothing doc (FormattingOptions 2 True Nothing Nothing Nothing)+ expectProgressReports ["Formatting Format.hs"]+ , ignoreTestBecause "no liquid Haskell support" $+ testCase "liquid haskell plugin sends progress notifications" $ do+ runSession hlsCommand progressCaps "test/testdata" $ do+ doc <- openDoc "liquid/Evens.hs" "haskell"+ let config = def{liquidOn = True, hlintOn = False}+ sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config))+ sendNotification STextDocumentDidSave (DidSaveTextDocumentParams doc Nothing)+ expectProgressReports ["Running Liquid Haskell on Evens.hs"]+ ]++formatLspConfig :: Value -> Value+formatLspConfig provider = object ["haskell" .= object ["formattingProvider" .= (provider :: Value)]]++progressCaps :: ClientCapabilities+progressCaps = fullCaps{_window = Just (WindowClientCapabilities (Just True))}++data CollectedProgressNotification+ = CreateM WorkDoneProgressCreateParams+ | BeginM (ProgressParams WorkDoneProgressBeginParams)+ | ProgressM (ProgressParams WorkDoneProgressReportParams)+ | EndM (ProgressParams WorkDoneProgressEndParams)++{- | Test that the server is correctly producing a sequence of progress related+ messages. Each create must be pair with a corresponding begin and end,+ optionally with some progress in between. Tokens must match. The begin+ messages have titles describing the work that is in-progress, we check that+ the titles we see are those we expect.+-}+expectProgressReports :: [Text] -> Session ()+expectProgressReports xs = expectProgressReports' [] xs+ where+ expectProgressReports' [] [] = return ()+ expectProgressReports' tokens expectedTitles =+ do+ skipManyTill anyMessage (create <|> begin <|> progress <|> end)+ >>= \case+ CreateM msg ->+ expectProgressReports' (token msg : tokens) expectedTitles+ BeginM msg -> do+ liftIO $ token msg `expectElem` tokens+ expectProgressReports' tokens (delete (title msg) expectedTitles)+ ProgressM msg -> do+ liftIO $ token msg `expectElem` tokens+ expectProgressReports' tokens expectedTitles+ EndM msg -> do+ liftIO $ token msg `expectElem` tokens+ expectProgressReports' (delete (token msg) tokens) expectedTitles+ title msg = msg ^. L.value . L.title+ token msg = msg ^. L.token+ create = CreateM . view L.params <$> message SWindowWorkDoneProgressCreate+ begin = BeginM <$> satisfyMaybe (\case+ FromServerMess SProgress (NotificationMessage _ _ (ProgressParams t (Begin x))) -> Just (ProgressParams t x)+ _ -> Nothing)+ progress = ProgressM <$> satisfyMaybe (\case+ FromServerMess SProgress (NotificationMessage _ _ (ProgressParams t (Report x))) -> Just (ProgressParams t x)+ _ -> Nothing)+ end = EndM <$> satisfyMaybe (\case+ FromServerMess SProgress (NotificationMessage _ _ (ProgressParams t (End x))) -> Just (ProgressParams t x)+ _ -> Nothing)+ expectElem a as = a `elem` as @? "Unexpected " ++ show a
@@ -1,36 +1,31 @@-module Reference (tests) where - -import Control.Lens -import Control.Monad.IO.Class -import Data.List -import Language.LSP.Test -import Language.LSP.Types -import Language.LSP.Types.Lens -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.ExpectedFailure (ignoreTestBecause) -import Test.Tasty.HUnit -import Data.Coerce - -tests :: TestTree -tests = testGroup "references" [ - ignoreTestBecause "Broken" $ testCase "works with definitions" $ runSession hlsCommand fullCaps "test/testdata" $ do - doc <- openDoc "References.hs" "haskell" - let pos = Position 2 7 -- foo = bar <-- - refs <- getReferences doc pos True - liftIO $ map (Location (doc ^. uri)) [ - mkRange 4 0 4 3 - , mkRange 8 11 8 14 - , mkRange 7 7 7 10 - , mkRange 4 14 4 17 - , mkRange 4 0 4 3 - , mkRange 2 6 2 9 - ] `isInfixOf` coerce refs @? "Contains references" - -- TODO: Respect withDeclaration parameter - -- ignoreTestBecause "Broken" $ testCase "works without definitions" $ runSession hlsCommand fullCaps "test/testdata" $ do - -- doc <- openDoc "References.hs" "haskell" - -- let pos = Position 2 7 -- foo = bar <-- - -- refs <- getReferences doc pos False - -- liftIO $ refs `shouldNotContain` [Location (doc ^. uri) (mkRange 4 0 4 3)] - ] - where mkRange sl sc el ec = Range (Position sl sc) (Position el ec) +module Reference (tests) where++import Control.Lens+import Data.Coerce+import Data.List+import Language.LSP.Types.Lens+import Test.Hls+import Test.Hls.Command++tests :: TestTree+tests = testGroup "references" [+ ignoreTestBecause "Broken" $ testCase "works with definitions" $ runSession hlsCommand fullCaps "test/testdata" $ do+ doc <- openDoc "References.hs" "haskell"+ let pos = Position 2 7 -- foo = bar <--+ refs <- getReferences doc pos True+ liftIO $ map (Location (doc ^. uri)) [+ mkRange 4 0 4 3+ , mkRange 8 11 8 14+ , mkRange 7 7 7 10+ , mkRange 4 14 4 17+ , mkRange 4 0 4 3+ , mkRange 2 6 2 9+ ] `isInfixOf` coerce refs @? "Contains references"+ -- TODO: Respect withDeclaration parameter+ -- ignoreTestBecause "Broken" $ testCase "works without definitions" $ runSession hlsCommand fullCaps "test/testdata" $ do+ -- doc <- openDoc "References.hs" "haskell"+ -- let pos = Position 2 7 -- foo = bar <--+ -- refs <- getReferences doc pos False+ -- liftIO $ refs `shouldNotContain` [Location (doc ^. uri) (mkRange 4 0 4 3)]+ ]+ where mkRange sl sc el ec = Range (Position sl sc) (Position el ec)
@@ -1,28 +1,23 @@-{-# LANGUAGE OverloadedStrings #-} -module Rename (tests) where - -import Control.Monad.IO.Class (liftIO) -import Language.LSP.Test -import Language.LSP.Types -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.HUnit -import Test.Tasty.ExpectedFailure (ignoreTestBecause) - -tests :: TestTree -tests = testGroup "rename" [ - ignoreTestBecause "no symbol renaming (yet!)" $ - testCase "works" $ - runSession hlsCommand fullCaps "test/testdata/rename" $ do - doc <- openDoc "Rename.hs" "haskell" - rename doc (Position 3 1) "baz" -- foo :: Int -> Int - contents <- documentContents doc - let expected = - "main = do\n\ - \ x <- return $ baz 42\n\ - \ return (baz x)\n\ - \baz :: Int -> Int\n\ - \baz x = x + 1\n\ - \bar = (+ 1) . baz\n" - liftIO $ contents @?= expected - ] +{-# LANGUAGE OverloadedStrings #-}+module Rename (tests) where++import Test.Hls+import Test.Hls.Command++tests :: TestTree+tests = testGroup "rename" [+ ignoreTestBecause "no symbol renaming (yet!)" $+ testCase "works" $+ runSession hlsCommand fullCaps "test/testdata/rename" $ do+ doc <- openDoc "Rename.hs" "haskell"+ rename doc (Position 3 1) "baz" -- foo :: Int -> Int+ contents <- documentContents doc+ let expected =+ "main = do\n\+ \ x <- return $ baz 42\n\+ \ return (baz x)\n\+ \baz :: Int -> Int\n\+ \baz x = x + 1\n\+ \bar = (+ 1) . baz\n"+ liftIO $ contents @?= expected+ ]
@@ -1,134 +0,0 @@-{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE ViewPatterns #-} -{-# LANGUAGE CPP #-} -{-# LANGUAGE DuplicateRecordFields #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE TypeOperators #-} - -module Splice (tests) where - -import Control.Applicative.Combinators -import Control.Monad -import Control.Monad.IO.Class -import Data.List (find) -import Data.Text (Text) -import qualified Data.Text as T -import qualified Data.Text.IO as T -import Ide.Plugin.Splice.Types -import Language.LSP.Test -import Language.LSP.Types -import System.Directory -import System.FilePath -import System.Time.Extra (sleep) -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.HUnit - -tests :: TestTree -tests = - testGroup - "splice" - [ goldenTest "TSimpleExp.hs" Inplace 6 15 - , goldenTest "TSimpleExp.hs" Inplace 6 24 - , goldenTest "TTypeAppExp.hs" Inplace 7 5 - , goldenTest "TErrorExp.hs" Inplace 6 15 - , goldenTest "TErrorExp.hs" Inplace 6 51 - , goldenTest "TQQExp.hs" Inplace 6 17 - , goldenTest "TQQExp.hs" Inplace 6 25 - , goldenTest "TQQExpError.hs" Inplace 6 13 - , goldenTest "TQQExpError.hs" Inplace 6 22 - , testGroup "Pattern Splices" - [ goldenTest "TSimplePat.hs" Inplace 6 3 - , goldenTest "TSimplePat.hs" Inplace 6 22 - , goldenTest "TSimplePat.hs" Inplace 6 3 - , goldenTest "TSimplePat.hs" Inplace 6 22 - , goldenTest "TErrorPat.hs" Inplace 6 3 - , goldenTest "TErrorPat.hs" Inplace 6 18 - , goldenTest "TQQPat.hs" Inplace 6 3 - , goldenTest "TQQPat.hs" Inplace 6 11 - , goldenTest "TQQPatError.hs" Inplace 6 3 - , goldenTest "TQQPatError.hs" Inplace 6 11 - ] - , goldenTest "TSimpleType.hs" Inplace 5 12 - , goldenTest "TSimpleType.hs" Inplace 5 22 - , goldenTest "TTypeTypeError.hs" Inplace 7 12 - , goldenTest "TTypeTypeError.hs" Inplace 7 52 - , goldenTest "TQQType.hs" Inplace 8 19 - , goldenTest "TQQType.hs" Inplace 8 28 - , goldenTest "TQQTypeTypeError.hs" Inplace 8 19 - , goldenTest "TQQTypeTypeError.hs" Inplace 8 28 - , goldenTest "TSimpleDecl.hs" Inplace 8 1 - , goldenTest "TQQDecl.hs" Inplace 5 1 - , goldenTestWithEdit "TTypeKindError.hs" Inplace 7 9 - , goldenTestWithEdit "TDeclKindError.hs" Inplace 8 1 - ] - -goldenTest :: FilePath -> ExpandStyle -> Int -> Int -> TestTree -goldenTest input tc line col = - testCase (input <> " (golden)") $ do - runSession hlsCommand fullCaps spliceTestPath $ do - doc <- openDoc input "haskell" - _ <- waitForDiagnostics - actions <- getCodeActions doc $ pointRange line col - case find ((== Just (toExpandCmdTitle tc)) . codeActionTitle) actions of - Just (InR CodeAction {_command = Just c}) -> do - executeCommand c - _resp <- skipManyTill anyMessage (message SWorkspaceApplyEdit) - edited <- documentContents doc - let expected_name = spliceTestPath </> input <.> "expected" - -- Write golden tests if they don't already exist - liftIO $ - (doesFileExist expected_name >>=) $ - flip unless $ do - T.writeFile expected_name edited - expected <- liftIO $ T.readFile expected_name - liftIO $ edited @?= expected - _ -> liftIO $ assertFailure "No CodeAction detected" - -goldenTestWithEdit :: FilePath -> ExpandStyle -> Int -> Int -> TestTree -goldenTestWithEdit input tc line col = - testCase (input <> " (golden)") $ do - runSession hlsCommand fullCaps spliceTestPath $ do - doc <- openDoc input "haskell" - orig <- documentContents doc - let lns = T.lines orig - theRange = - Range - { _start = Position 0 0 - , _end = Position (length lns + 1) 1 - } - liftIO $ sleep 3 - alt <- liftIO $ T.readFile (spliceTestPath </> input <.> "error") - void $ applyEdit doc $ TextEdit theRange alt - changeDoc doc [TextDocumentContentChangeEvent (Just theRange) Nothing alt] - void waitForDiagnostics - actions <- getCodeActions doc $ pointRange line col - case find ((== Just (toExpandCmdTitle tc)) . codeActionTitle) actions of - Just (InR CodeAction {_command = Just c}) -> do - executeCommand c - _resp <- skipManyTill anyMessage (message SWorkspaceApplyEdit) - edited <- documentContents doc - let expected_name = spliceTestPath </> input <.> "expected" - -- Write golden tests if they don't already exist - liftIO $ - (doesFileExist expected_name >>=) $ - flip unless $ do - T.writeFile expected_name edited - expected <- liftIO $ T.readFile expected_name - liftIO $ edited @?= expected - _ -> liftIO $ assertFailure "No CodeAction detected" - -spliceTestPath :: FilePath -spliceTestPath = "test/testdata/splice" - -pointRange :: Int -> Int -> Range -pointRange - (subtract 1 -> line) - (subtract 1 -> col) = - Range (Position line col) (Position line $ col + 1) - --- | Get the title of a code action. -codeActionTitle :: (Command |? CodeAction) -> Maybe Text -codeActionTitle InL{} = Nothing -codeActionTitle (InR(CodeAction title _ _ _ _ _ _)) = Just title
@@ -1,157 +1,153 @@-{-# LANGUAGE OverloadedStrings #-} -module Symbol (tests) where - -import Control.Lens (to, ix, (^?), _Just) -import Control.Monad.IO.Class -import Data.List -import Language.LSP.Test as Test -import Language.LSP.Types -import qualified Language.LSP.Types.Lens as L -import Language.LSP.Types.Capabilities -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.ExpectedFailure (ignoreTestBecause) -import Test.Tasty.HUnit - -tests :: TestTree -tests = testGroup "document symbols" [ - pre310Tests - , v310Tests - ] - -v310Tests :: TestTree -v310Tests = testGroup "3.10 hierarchical document symbols" [ - testCase "provides nested data types and constructors" $ runSession hlsCommand fullCaps "test/testdata" $ do - doc <- openDoc "Symbols.hs" "haskell" - Left symbs <- getDocumentSymbols doc - - let myData = DocumentSymbol "MyData" Nothing SkStruct Nothing myDataR myDataSR (Just (List [a, b])) - a = DocumentSymbol "A" Nothing SkConstructor Nothing aR aSR Nothing - b = DocumentSymbol "B" Nothing SkConstructor Nothing bR bSR Nothing - let myData' = symbs ^? ix 0 . L.children . _Just .to fromList . ix 2 - - liftIO $ Just myData == myData' @? "Contains symbol" - - , ignoreTestBecause "extracting symbols from nested wheres not supported" $ testCase "provides nested where functions" $ runSession hlsCommand fullCaps "test/testdata" $ do - doc <- openDoc "Symbols.hs" "haskell" - Left symbs <- getDocumentSymbols doc - - let foo = DocumentSymbol "foo" Nothing SkFunction Nothing fooR fooSR (Just (List [bar])) - bar = DocumentSymbol "bar" Nothing SkFunction Nothing barR barSR (Just (List [dog, cat])) - dog = DocumentSymbol "dog" Nothing SkVariable Nothing dogR dogSR (Just mempty) - cat = DocumentSymbol "cat" Nothing SkVariable Nothing catR catSR (Just mempty) - let foo' = symbs ^? ix 0 . L.children . _Just .to fromList . ix 1 - - liftIO $ Just foo == foo' @? "Contains symbol" - - , ignoreTestBecause "extracting pattern synonym symbols not supported" $ testCase "provides pattern synonyms" $ runSession hlsCommand fullCaps "test/testdata" $ do - doc <- openDoc "Symbols.hs" "haskell" - Left symbs <- getDocumentSymbols doc - - let testPattern = DocumentSymbol "TestPattern" - Nothing SkFunction Nothing testPatternR testPatternSR (Just mempty) - let testPattern' = symbs ^? ix 0 . L.children . _Just .to fromList . ix 3 - - liftIO $ Just testPattern == testPattern' @? "Contains symbol" - - , testCase "provides imports" $ runSession hlsCommand fullCaps "test/testdata" $ do - doc <- openDoc "Symbols.hs" "haskell" - Left symbs <- getDocumentSymbols doc - - let imports = DocumentSymbol "imports" Nothing SkModule Nothing importsR importsSR (Just (List [importDataMaybe])) - importDataMaybe = DocumentSymbol "import Data.Maybe" Nothing SkModule Nothing importDataMaybeR importDataMaybeSR Nothing - let imports' = symbs ^? ix 0 . L.children . _Just .to fromList . ix 0 - - liftIO $ Just imports == imports' @? "Contains symbol" - ] - -pre310Tests :: TestTree -pre310Tests = testGroup "pre 3.10 symbol information" [ - testCase "provides nested data types and constructors" $ runSession hlsCommand oldCaps "test/testdata" $ do - doc@(TextDocumentIdentifier testUri) <- openDoc "Symbols.hs" "haskell" - Right symbs <- getDocumentSymbols doc - - let myData = SymbolInformation "MyData" SkStruct Nothing (Location testUri myDataR) (Just "Symbols") - a = SymbolInformation "A" SkConstructor Nothing (Location testUri aR) (Just "MyData") - b = SymbolInformation "B" SkConstructor Nothing (Location testUri bR) (Just "MyData") - - liftIO $ [myData, a, b] `isInfixOf` symbs @? "Contains symbols" - - , ignoreTestBecause "extracting symbols from nested wheres not supported" $ testCase "provides nested where functions" $ runSession hlsCommand oldCaps "test/testdata" $ do - doc@(TextDocumentIdentifier testUri) <- openDoc "Symbols.hs" "haskell" - Right symbs <- getDocumentSymbols doc - - let foo = SymbolInformation "foo" SkFunction Nothing (Location testUri fooR) (Just "Symbols") - bar = SymbolInformation "bar" SkFunction Nothing (Location testUri barR) (Just "foo") - dog = SymbolInformation "dog" SkVariable Nothing (Location testUri dogR) (Just "bar") - cat = SymbolInformation "cat" SkVariable Nothing (Location testUri catR) (Just "bar") - - -- Order is important! - liftIO $ [foo, bar, dog, cat] `isInfixOf` symbs @? "Contains symbols" - - , ignoreTestBecause "extracting pattern synonym symbols not supported" $ testCase "provides pattern synonyms" $ runSession hlsCommand oldCaps "test/testdata" $ do - doc@(TextDocumentIdentifier testUri) <- openDoc "Symbols.hs" "haskell" - Right symbs <- getDocumentSymbols doc - - let testPattern = SymbolInformation "TestPattern" - SkFunction Nothing (Location testUri testPatternR) (Just "Symbols") - - liftIO $ testPattern `elem` symbs @? "Contains symbols" - - , testCase "provides imports" $ runSession hlsCommand oldCaps "test/testdata" $ do - doc@(TextDocumentIdentifier testUri) <- openDoc "Symbols.hs" "haskell" - Right symbs <- getDocumentSymbols doc - - let imports = SymbolInformation "imports" SkModule Nothing (Location testUri importsR) (Just "Symbols") - importDataMaybe = SymbolInformation "import Data.Maybe" SkModule Nothing (Location testUri importDataMaybeR) (Just "imports") - - liftIO $ [imports, importDataMaybe] `isInfixOf` symbs @? "Contains symbol" - ] - -oldCaps :: ClientCapabilities -oldCaps = capsForVersion (LSPVersion 3 9) - -fromList :: List a -> [a] -fromList (List a) = a - --- Some common ranges and selection ranges in Symbols.hs -importsR :: Range -importsR = Range (Position 3 0) (Position 3 17) -importsSR :: Range -importsSR = Range (Position 3 0) (Position 3 17) -importDataMaybeR :: Range -importDataMaybeR = Range (Position 3 0) (Position 3 17) -importDataMaybeSR :: Range -importDataMaybeSR = Range (Position 3 0) (Position 3 17) -fooSR :: Range -fooSR = Range (Position 5 0) (Position 7 43) -fooR :: Range -fooR = Range (Position 5 0) (Position 7 43) -barSR :: Range -barSR = Range (Position 6 8) (Position 6 11) -barR :: Range -barR = Range (Position 6 8) (Position 7 43) -dogSR :: Range -dogSR = Range (Position 7 17) (Position 7 20) -dogR :: Range -dogR = Range (Position 7 16) (Position 7 43) -catSR :: Range -catSR = Range (Position 7 22) (Position 7 25) -catR :: Range -catR = Range (Position 7 16) (Position 7 43) -myDataSR :: Range -myDataSR = Range (Position 9 0) (Position 10 22) -myDataR :: Range -myDataR = Range (Position 9 0) (Position 10 22) -aSR :: Range -aSR = Range (Position 9 14) (Position 9 15) -aR :: Range -aR = Range (Position 9 14) (Position 9 19) -bSR :: Range -bSR = Range (Position 10 14) (Position 10 15) -bR :: Range -bR = Range (Position 10 14) (Position 10 22) -testPatternSR :: Range -testPatternSR = Range (Position 13 8) (Position 13 19) -testPatternR :: Range -testPatternR = Range (Position 13 0) (Position 13 27) +{-# LANGUAGE OverloadedStrings #-}+module Symbol (tests) where++import Control.Lens (_Just, ix, to, (^?))+import Data.List+import Language.LSP.Test as Test+import Language.LSP.Types.Capabilities+import qualified Language.LSP.Types.Lens as L+import Test.Hls+import Test.Hls.Command++tests :: TestTree+tests = testGroup "document symbols" [+ pre310Tests+ , v310Tests+ ]++v310Tests :: TestTree+v310Tests = testGroup "3.10 hierarchical document symbols" [+ testCase "provides nested data types and constructors" $ runSession hlsCommand fullCaps "test/testdata" $ do+ doc <- openDoc "Symbols.hs" "haskell"+ Left symbs <- getDocumentSymbols doc++ let myData = DocumentSymbol "MyData" Nothing SkStruct Nothing Nothing myDataR myDataSR (Just (List [a, b]))+ a = DocumentSymbol "A" Nothing SkConstructor Nothing Nothing aR aSR Nothing+ b = DocumentSymbol "B" Nothing SkConstructor Nothing Nothing bR bSR Nothing+ let myData' = symbs ^? ix 0 . L.children . _Just .to fromList . ix 2++ liftIO $ Just myData == myData' @? "Contains symbol"++ , ignoreTestBecause "extracting symbols from nested wheres not supported" $ testCase "provides nested where functions" $ runSession hlsCommand fullCaps "test/testdata" $ do+ doc <- openDoc "Symbols.hs" "haskell"+ Left symbs <- getDocumentSymbols doc++ let foo = DocumentSymbol "foo" Nothing SkFunction Nothing Nothing fooR fooSR (Just (List [bar]))+ bar = DocumentSymbol "bar" Nothing SkFunction Nothing Nothing barR barSR (Just (List [dog, cat]))+ dog = DocumentSymbol "dog" Nothing SkVariable Nothing Nothing dogR dogSR (Just mempty)+ cat = DocumentSymbol "cat" Nothing SkVariable Nothing Nothing catR catSR (Just mempty)+ let foo' = symbs ^? ix 0 . L.children . _Just .to fromList . ix 1++ liftIO $ Just foo == foo' @? "Contains symbol"++ , ignoreTestBecause "extracting pattern synonym symbols not supported" $ testCase "provides pattern synonyms" $ runSession hlsCommand fullCaps "test/testdata" $ do+ doc <- openDoc "Symbols.hs" "haskell"+ Left symbs <- getDocumentSymbols doc++ let testPattern = DocumentSymbol "TestPattern"+ Nothing SkFunction Nothing Nothing testPatternR testPatternSR (Just mempty)+ let testPattern' = symbs ^? ix 0 . L.children . _Just .to fromList . ix 3++ liftIO $ Just testPattern == testPattern' @? "Contains symbol"++ , testCase "provides imports" $ runSession hlsCommand fullCaps "test/testdata" $ do+ doc <- openDoc "Symbols.hs" "haskell"+ Left symbs <- getDocumentSymbols doc++ let imports = DocumentSymbol "imports" Nothing SkModule Nothing Nothing importsR importsSR (Just (List [importDataMaybe]))+ importDataMaybe = DocumentSymbol "import Data.Maybe" Nothing SkModule Nothing Nothing importDataMaybeR importDataMaybeSR Nothing+ let imports' = symbs ^? ix 0 . L.children . _Just .to fromList . ix 0++ liftIO $ Just imports == imports' @? "Contains symbol"+ ]++pre310Tests :: TestTree+pre310Tests = testGroup "pre 3.10 symbol information" [+ testCase "provides nested data types and constructors" $ runSession hlsCommand oldCaps "test/testdata" $ do+ doc@(TextDocumentIdentifier testUri) <- openDoc "Symbols.hs" "haskell"+ Right symbs <- getDocumentSymbols doc++ let myData = SymbolInformation "MyData" SkStruct Nothing Nothing (Location testUri myDataR) (Just "Symbols")+ a = SymbolInformation "A" SkConstructor Nothing Nothing (Location testUri aR) (Just "MyData")+ b = SymbolInformation "B" SkConstructor Nothing Nothing (Location testUri bR) (Just "MyData")++ liftIO $ [myData, a, b] `isInfixOf` symbs @? "Contains symbols"++ , ignoreTestBecause "extracting symbols from nested wheres not supported" $ testCase "provides nested where functions" $ runSession hlsCommand oldCaps "test/testdata" $ do+ doc@(TextDocumentIdentifier testUri) <- openDoc "Symbols.hs" "haskell"+ Right symbs <- getDocumentSymbols doc++ let foo = SymbolInformation "foo" SkFunction Nothing Nothing (Location testUri fooR) (Just "Symbols")+ bar = SymbolInformation "bar" SkFunction Nothing Nothing (Location testUri barR) (Just "foo")+ dog = SymbolInformation "dog" SkVariable Nothing Nothing (Location testUri dogR) (Just "bar")+ cat = SymbolInformation "cat" SkVariable Nothing Nothing (Location testUri catR) (Just "bar")++ -- Order is important!+ liftIO $ [foo, bar, dog, cat] `isInfixOf` symbs @? "Contains symbols"++ , ignoreTestBecause "extracting pattern synonym symbols not supported" $ testCase "provides pattern synonyms" $ runSession hlsCommand oldCaps "test/testdata" $ do+ doc@(TextDocumentIdentifier testUri) <- openDoc "Symbols.hs" "haskell"+ Right symbs <- getDocumentSymbols doc++ let testPattern = SymbolInformation "TestPattern"+ SkFunction Nothing Nothing (Location testUri testPatternR) (Just "Symbols")++ liftIO $ testPattern `elem` symbs @? "Contains symbols"++ , testCase "provides imports" $ runSession hlsCommand oldCaps "test/testdata" $ do+ doc@(TextDocumentIdentifier testUri) <- openDoc "Symbols.hs" "haskell"+ Right symbs <- getDocumentSymbols doc++ let imports = SymbolInformation "imports" SkModule Nothing Nothing (Location testUri importsR) (Just "Symbols")+ importDataMaybe = SymbolInformation "import Data.Maybe" SkModule Nothing Nothing (Location testUri importDataMaybeR) (Just "imports")++ liftIO $ [imports, importDataMaybe] `isInfixOf` symbs @? "Contains symbol"+ ]++oldCaps :: ClientCapabilities+oldCaps = capsForVersion (LSPVersion 3 9)++fromList :: List a -> [a]+fromList (List a) = a++-- Some common ranges and selection ranges in Symbols.hs+importsR :: Range+importsR = Range (Position 3 0) (Position 3 17)+importsSR :: Range+importsSR = Range (Position 3 0) (Position 3 17)+importDataMaybeR :: Range+importDataMaybeR = Range (Position 3 0) (Position 3 17)+importDataMaybeSR :: Range+importDataMaybeSR = Range (Position 3 0) (Position 3 17)+fooSR :: Range+fooSR = Range (Position 5 0) (Position 7 43)+fooR :: Range+fooR = Range (Position 5 0) (Position 7 43)+barSR :: Range+barSR = Range (Position 6 8) (Position 6 11)+barR :: Range+barR = Range (Position 6 8) (Position 7 43)+dogSR :: Range+dogSR = Range (Position 7 17) (Position 7 20)+dogR :: Range+dogR = Range (Position 7 16) (Position 7 43)+catSR :: Range+catSR = Range (Position 7 22) (Position 7 25)+catR :: Range+catR = Range (Position 7 16) (Position 7 43)+myDataSR :: Range+myDataSR = Range (Position 9 0) (Position 10 22)+myDataR :: Range+myDataR = Range (Position 9 0) (Position 10 22)+aSR :: Range+aSR = Range (Position 9 14) (Position 9 15)+aR :: Range+aR = Range (Position 9 14) (Position 9 19)+bSR :: Range+bSR = Range (Position 10 14) (Position 10 15)+bR :: Range+bR = Range (Position 10 14) (Position 10 22)+testPatternSR :: Range+testPatternSR = Range (Position 13 8) (Position 13 19)+testPatternR :: Range+testPatternR = Range (Position 13 0) (Position 13 27)
@@ -1,47 +1,43 @@-module TypeDefinition (tests) where - -import Control.Monad.IO.Class -import Data.Tuple.Extra (first3) -import Language.LSP.Test -import Language.LSP.Types -import System.FilePath ((</>)) -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.HUnit - -tests :: TestTree -tests = testGroup "type definitions" [ - testCase "finds local definition of record variable" - $ getTypeDefinitionTest' 10 23 7 0 - , testCase "finds local definition of newtype variable" - $ getTypeDefinitionTest' 15 21 12 0 - , testCase "finds local definition of sum type variable" - $ getTypeDefinitionTest' 20 13 17 0 - , knownBrokenForGhcVersions [GHC88] "Definition of sum type not found from data constructor in GHC 8.8.x" $ - testCase "finds local definition of sum type constructor" - $ getTypeDefinitionTest' 23 7 17 0 - , testCase "finds non-local definition of type def" - $ getTypeDefinitionTest' 29 19 26 0 - , testCase "find local definition of type def" - $ getTypeDefinitionTest' 34 16 31 0 - , testCase "find type-definition of type def in component" - $ getTypeDefinitionTest ("src/Lib2.hs", 12, 20) [("src/Lib.hs", 7, 0)] - , testCase "find definition of parameterized data type" - $ getTypeDefinitionTest ("src/Lib.hs", 39, 19) [ ("src/Lib.hs", 36, 0) - , ("src/Lib.hs", 38, 0)] - ] - -definitionsPath :: FilePath -definitionsPath = "test/testdata/gototest" - -getTypeDefinitionTest :: SymbolLocation -> [SymbolLocation] -> Assertion -getTypeDefinitionTest (symbolFile, symbolLine, symbolCol) definitionLocations = - failIfSessionTimeout . runSession (hlsCommand ++ " --test") fullCaps definitionsPath $ do - doc <- openDoc symbolFile "haskell" - InL defs <- getTypeDefinitions doc $ Position symbolLine symbolCol - liftIO $ defs `expectSameLocations` map (first3 (definitionsPath </>)) definitionLocations - -getTypeDefinitionTest' :: Int -> Int -> Int -> Int -> Assertion -getTypeDefinitionTest' symbolLine symbolCol definitionLine definitionCol = - getTypeDefinitionTest ("src/Lib.hs", symbolLine, symbolCol) - [("src/Lib.hs", definitionLine, definitionCol)] +module TypeDefinition (tests) where++import Data.Tuple.Extra (first3)+import System.FilePath ((</>))+import Test.Hls+import Test.Hls.Command++tests :: TestTree+tests = testGroup "type definitions" [+ testCase "finds local definition of record variable"+ $ getTypeDefinitionTest' 10 23 7 0+ , testCase "finds local definition of newtype variable"+ $ getTypeDefinitionTest' 15 21 12 0+ , testCase "finds local definition of sum type variable"+ $ getTypeDefinitionTest' 20 13 17 0+ , knownBrokenForGhcVersions [GHC88] "Definition of sum type not found from data constructor in GHC 8.8.x" $+ testCase "finds local definition of sum type constructor"+ $ getTypeDefinitionTest' 23 7 17 0+ , testCase "finds non-local definition of type def"+ $ getTypeDefinitionTest' 29 19 26 0+ , testCase "find local definition of type def"+ $ getTypeDefinitionTest' 34 16 31 0+ , testCase "find type-definition of type def in component"+ $ getTypeDefinitionTest ("src/Lib2.hs", 12, 20) [("src/Lib.hs", 7, 0)]+ , testCase "find definition of parameterized data type"+ $ getTypeDefinitionTest ("src/Lib.hs", 39, 19) [ ("src/Lib.hs", 36, 0)+ , ("src/Lib.hs", 38, 0)]+ ]++definitionsPath :: FilePath+definitionsPath = "test/testdata/gototest"++getTypeDefinitionTest :: SymbolLocation -> [SymbolLocation] -> Assertion+getTypeDefinitionTest (symbolFile, symbolLine, symbolCol) definitionLocations =+ failIfSessionTimeout . runSession (hlsCommand ++ " --test") fullCaps definitionsPath $ do+ doc <- openDoc symbolFile "haskell"+ InL defs <- getTypeDefinitions doc $ Position symbolLine symbolCol+ liftIO $ defs `expectSameLocations` map (first3 (definitionsPath </>)) definitionLocations++getTypeDefinitionTest' :: Int -> Int -> Int -> Int -> Assertion+getTypeDefinitionTest' symbolLine symbolCol definitionLine definitionCol =+ getTypeDefinitionTest ("src/Lib.hs", symbolLine, symbolCol)+ [("src/Lib.hs", definitionLine, definitionCol)]
@@ -0,0 +1,2 @@+main :: IO ()+main = when True $ putStrLn "hello"
@@ -0,0 +1,3 @@+module CodeActionOnly where+foo = bar+ where bar = id Nothing
@@ -0,0 +1,2 @@+main = butStrLn "hello"+foo = putStrn "world"
@@ -0,0 +1,13 @@+module Main where++main = putStrLn "hello"++foo :: Int+foo = bb++bb = 5++baz = do+ putStrLn "hello"++f x = x+1
@@ -0,0 +1,15 @@+module Main where++main = putStrLn "hello"++foo :: Int+foo = bb++bb = 5++bug -- no hlint returned because of this, despite redundant do below++baz = do+ putStrLn "hello"++f x = x+1
@@ -0,0 +1,2 @@+main :: IO Int+main = return "yow
@@ -0,0 +1,5 @@+module Highlight where+foo :: Int+foo = 3+bar = foo+ where baz = let x = foo in id x
@@ -0,0 +1,2 @@+main :: IO Int+main = return $ sum [1,2,3]
@@ -0,0 +1,9 @@+main = return ()++foo = bar++bar = let x = bar 42 in const "hello"++baz = do+ x <- bar 23+ return $ bar 14
@@ -0,0 +1,14 @@+{-# LANGUAGE PatternSynonyms #-}+module Symbols where++import Data.Maybe++foo = bar+ where bar = 42 + dog+ where (dog, cat) = (1234, "meow")++data MyData = A Int+ | B String++pattern TestPattern :: Int -> MyData+pattern TestPattern x = A x
@@ -0,0 +1,5 @@+{-# OPTIONS_GHC -Wall #-}+module TopLevelSignature where+main = do+ putStrLn "Hello"+ return ()
@@ -0,0 +1,3 @@+module TypedHoles where+foo :: [Int] -> Int+foo x = _
@@ -0,0 +1,6 @@+module TypedHoles2 (foo2) where+newtype A = A Int+foo2 :: [A] -> A+foo2 x = _+ where+ stuff (A a) = A (a + 1)
@@ -0,0 +1,6 @@+{-# OPTIONS_GHC -Wall #-}+module UnusedTerm () where+imUnused :: Int -> Int+imUnused 1 = 1+imUnused 2 = 2+imUnused _ = 3
@@ -0,0 +1,3 @@+import Data.Text+foo = pack "I'm a Text"+main = putStrLn "hello"
@@ -0,0 +1,14 @@+name: add-package-test+version: 0.1.0.0+license: BSD3+author: Luke Lau+maintainer: luke_lau@icloud.com+build-type: Simple+extra-source-files: ChangeLog.md+cabal-version: >=1.10++executable AddPackage+ exposed-modules: ./.+ main-is: AddPackage.hs+ build-depends: base >=4.7 && <5+ default-language: Haskell2010
@@ -0,0 +1,4 @@+module AddPackage where ++import Data.Text+foo = pack "I'm a Text"
@@ -0,0 +1,14 @@+name: add-package-test+version: 0.1.0.0+license: BSD3+author: Luke Lau+maintainer: luke_lau@icloud.com+build-type: Simple+extra-source-files: ChangeLog.md+cabal-version: >=1.10++library+ exposed-modules: AddPackage+ build-depends: base >=4.7 && <5+ -- hs-source-dirs:+ default-language: Haskell2010
@@ -0,0 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}++import Codec.Compression.GZip++main = return $ compress "hello"
@@ -0,0 +1,37 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.32.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: 69241e1f4f912f034502d225d2017f035c38062080733108c11cd3d111cb9007++name: asdf+version: 0.1.0.0+description: Please see the README on GitHub at <https://github.com/githubuser/asdf#readme>+homepage: https://github.com/githubuser/asdf#readme+bug-reports: https://github.com/githubuser/asdf/issues+author: Author name here+maintainer: example@example.com+copyright: 2018 Author name here+license: BSD3+build-type: Simple+extra-source-files:+ README.md+ ChangeLog.md++source-repository head+ type: git+ location: https://github.com/githubuser/asdf++executable asdf-exe+ main-is: Main.hs+ other-modules:+ Asdf+ Paths_asdf+ hs-source-dirs:+ app+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ base >=4.7 && <5+ default-language: Haskell2010
@@ -0,0 +1,7 @@+{-# LANGUAGE OverloadedStrings #-}++module Asdf where++import Codec.Compression.GZip++main = return $ compress "hello"
@@ -0,0 +1,2 @@+import Data.Text+foo = pack "I'm a Text"
@@ -0,0 +1,12 @@+#! /usr/bin/env nix-shell+#! nix-shell --pure -i runghc -p "haskellPackages.ghcWithPackages (hp: with hp; [ turtle ])"++module AfterShebang where++data Record = Record+ { a :: Int,+ b :: Double,+ c :: String+ }++f Record{a, b} = a
@@ -0,0 +1,9 @@+module NamedFieldPuns where++data Record = Record+ { a :: Int,+ b :: Double,+ c :: String+ }++f Record{a, b} = a
@@ -0,0 +1,16 @@+module NeedsPragmas where++import GHC.Generics++main = putStrLn "hello"++type Foo = Int++instance Show Foo where+ show x = undefined++instance Show (Int,String) where+ show = undefined++data FFF a = FFF Int String a+ deriving (Generic,Functor,Traversable)
@@ -0,0 +1,5 @@+{-# LANGUAGE ScopedTypeVariables #-}+module TypeApplications where++foo :: forall a. a -> a+foo = id @a
@@ -0,0 +1,6 @@+cradle:+ direct:+ arguments:+ - "NeedsPragmas"+ - "TypeApplications"+ - "NamedFieldPuns"
@@ -0,0 +1,4 @@+module Foo where++foo :: Int+foo = 3
@@ -0,0 +1,16 @@+name: bad-cabal+version: 0.1.0.0+license: BSD3+author: Alan Zimmerman+maintainer: alan.zimm@gmail.com+build-type: Simple+extra-source-files: ChangeLog.md+cabal-version: >=1.10++library+ exposed-modules: Foo+ build-depends: base >=4.7 && <5+ -- missing dependency+ , does-not-exist+ -- hs-source-dirs:+ default-language: Haskell2010
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
@@ -0,0 +1,1 @@+packages: ./
@@ -0,0 +1,17 @@+cabal-version: >=1.10+name: implicit-exe+version: 0.1.0.0+license-file: LICENSE+build-type: Simple++library+ exposed-modules: Lib+ hs-source-dirs: src+ build-depends: base+ default-language: Haskell2010+++executable implicit-exe+ main-is: src/Exe.hs+ build-depends: base, implicit-exe+ default-language: Haskell2010
@@ -0,0 +1,4 @@++import Lib (someFunc)++main = someFunc
@@ -0,0 +1,4 @@+module Lib (someFunc) where++someFunc :: IO ()+someFunc = putStrLn "someFunc"
@@ -0,0 +1,15 @@+cabal-version: >=1.10+name: A+version: 0.1.0.0+build-type: Simple++library+ exposed-modules: MyLib+ build-depends: base+ default-language: Haskell2010++executable A+ main-is: Main.hs+ other-modules: MyLib+ build-depends: base, A+ default-language: Haskell2010
@@ -0,0 +1,8 @@+module Main where++import qualified MyLib (someFunc)++main :: IO ()+main = do+ putStrLn "Hello, Haskell!"+ MyLib.someFunc
@@ -0,0 +1,4 @@+module MyLib (someFunc) where++someFunc :: IO ()+someFunc = putStrLn "someFunc"
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
@@ -0,0 +1,15 @@+cabal-version: >=1.10+name: B+version: 0.1.0.0+build-type: Simple++library+ exposed-modules: MyLib+ build-depends: base+ default-language: Haskell2010++executable B+ main-is: Main.hs+ other-modules: MyLib+ build-depends: base, B+ default-language: Haskell2010
@@ -0,0 +1,8 @@+module Main where++import qualified MyLib (someFunc)++main :: IO ()+main = do+ putStrLn "Hello, Haskell!"+ MyLib.someFunc
@@ -0,0 +1,4 @@+module MyLib (someFunc) where++someFunc :: IO ()+someFunc = putStrLn "someFunc"
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
@@ -0,0 +1,9 @@+cabal-version: >=1.10+name: C+version: 0.1.0.0+build-type: Simple++library+ exposed-modules: MyLib+ build-depends: base+ default-language: Haskell2010
@@ -0,0 +1,4 @@+module MyLib (someFunc) where++someFunc :: IO ()+someFunc = putStrLn "someFunc"
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
@@ -0,0 +1,4 @@+packages:+ ./A/+ ./B/+ ./C/
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
@@ -0,0 +1,11 @@+cabal-version: >=1.10+name: multi-source-dirs+version: 0.1.0.0+license-file: LICENSE+build-type: Simple++library+ exposed-modules: Lib, BetterLib+ hs-source-dirs: src, src/input+ build-depends: base+ default-language: Haskell2010
@@ -0,0 +1,5 @@+module BetterLib where+++foo = 3+bar = "String"
@@ -0,0 +1,6 @@+module Lib where++foobar = 15++fizbuzz :: Int -> String+fizbuzz n = "Fizz"
@@ -0,0 +1,4 @@+module MyLib (someFunc) where++someFunc :: IO ()+someFunc = putStrLn "someFunc"
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
@@ -0,0 +1,10 @@+cabal-version: >=1.10+name: simple-cabal-test+version: 0.1.0.0+license-file: LICENSE+build-type: Simple++library+ exposed-modules: MyLib+ build-depends: base+ default-language: Haskell2010
@@ -0,0 +1,4 @@+module MyLib (someFunc) where++someFunc :: IO ()+someFunc = putStrLn "someFunc"
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
@@ -0,0 +1,10 @@+cabal-version: >=1.10+name: simple-stack-test+version: 0.1.0.0+license-file: LICENSE+build-type: Simple++library+ exposed-modules: MyLib+ build-depends: base+ default-language: Haskell2010
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
@@ -0,0 +1,8 @@+module Main where++import qualified MyLib (someFunc)++main :: IO ()+main = do+ putStrLn "Hello, Haskell!"+ MyLib.someFunc
@@ -0,0 +1,4 @@+module PluginLib (someFunc) where++someFunc :: IO ()+someFunc = putStrLn "someFunc"
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
@@ -0,0 +1,10 @@+cabal-version: >=1.10+name: plugins-api+version: 0.1.0.0+license-file: LICENSE+build-type: Simple++library+ exposed-modules: PluginLib+ build-depends: base+ default-language: Haskell2010
@@ -0,0 +1,6 @@+module MyLib (someFunc) where++import qualified PluginLib as L++someFunc :: IO ()+someFunc = L.someFunc
@@ -0,0 +1,17 @@+cabal-version: >=1.10+name: sub-package+version: 0.1.0.0+license-file: LICENSE+build-type: Simple++library+ exposed-modules: MyLib+ build-depends: base, plugins-api+ hs-source-dirs: src+ default-language: Haskell2010++executable sub-package+ main-is: Main.hs+ build-depends: base, sub-package+ hs-source-dirs: app+ default-language: Haskell2010
@@ -0,0 +1,9 @@+{-# LANGUAGE OverloadedStrings #-}+import Data.Maybe+import qualified Data.List++main :: IO ()+main = putStrLn "hello"++foo :: Either a b -> Either a b+foo = id
@@ -0,0 +1,4 @@+module Context where+import Control.Concurrent as Conc+foo :: Int -> Int -> Conc.MVar+foo x = abs 42
@@ -0,0 +1,5 @@+{-# LANGUAGE DuplicateRecordFields #-}+module DupRecFields where++newtype One = One { accessor :: Int }+newtype Two = Two { accessor :: Int }
@@ -0,0 +1,10 @@+name: completions+version: 0.1.0.0+cabal-version: >= 2.0+build-type: Simple++executable compl-exe+ other-modules: DupRecFields, Context+ main-is: Completion.hs+ default-language: Haskell2010+ build-depends: base
@@ -0,0 +1,6 @@+cradle:+ direct:+ arguments:+ - "Completion"+ - "Context"+ - "DupRecFields"
@@ -0,0 +1,20 @@+module ExampleContext (foo) where++import Data.List (find)+import Control.Monad hiding (fix)++foo :: Int -> Int+foo xs = bar xs + 1+ where+ bar :: Int -> Int+ bar x = x + 2++data Foo a = Foo a + deriving (Show)++class Bar a where+ bar :: a -> Integer++instance Integral a => Bar (Foo a) where+ bar (Foo a) = toInteger a+
@@ -0,0 +1,3 @@+module Foo.Bar where++
@@ -0,0 +1,3 @@+module Bar where++a = 42
@@ -0,0 +1,3 @@+module Foo (module Bar) where++import Bar
@@ -0,0 +1,10 @@+name: definitions+version: 0.1.0.0+cabal-version: >= 2.0+build-type: Simple++library+ exposed-modules: Foo+ other-modules: Bar+ default-language: Haskell2010+ build-depends: base
@@ -0,0 +1,16 @@+module Format where++import Data.Int+import Data.List+import Prelude++foo :: Int -> Int+foo 3 = 2+foo x = x++bar :: String -> IO String+bar s = do+ x <- return "hello"+ return "asdf"++data Baz = Baz { a :: Int, b :: String }
@@ -0,0 +1,17 @@+module Format where++import Data.List+import Prelude+import Data.Int++foo :: Int -> Int+foo 3 = 2+foo x = x++bar :: String -> IO String+bar s = do+ x <- return "hello"+ return "asdf"++data Baz = Baz { a :: Int, b :: String }+
@@ -0,0 +1,16 @@+module Format where++import Data.Int+import Data.List+import Prelude++foo :: Int -> Int+foo 3 = 2+foo x = x++bar :: String -> IO String+bar s = do+ x <- return "hello"+ return "asdf"++data Baz = Baz {a :: Int, b :: String}
@@ -0,0 +1,16 @@+module Format where++import Data.Int+import Data.List+import Prelude++foo :: Int -> Int+foo 3 = 2+foo x = x++bar :: String -> IO String+bar s = do+ x <- return "hello"+ return "asdf"++data Baz = Baz {a :: Int, b :: String}
@@ -0,0 +1,15 @@+module Format where+import Data.List++import Prelude+import Data.Int+foo :: Int -> Int+foo 3 = 2+foo x = x+bar :: String -> IO String+bar s = do+ x <- return "hello"+ return "asdf"++data Baz = Baz { a :: Int, b :: String }+
@@ -0,0 +1,15 @@+module Format where+import Data.List++import Prelude+import Data.Int+foo :: Int -> Int+foo 3 = 2+foo x = x+bar :: String -> IO String+bar s = do+ x <- return "hello"+ return "asdf"++data Baz = Baz { a :: Int, b :: String }+
@@ -0,0 +1,16 @@+module Format where++import Data.List++import Data.Int+import Prelude++foo :: Int -> Int+foo 3 = 2+foo x = x+bar :: String -> IO String+bar s = do+ x <- return "hello"+ return "asdf"++data Baz = Baz {a :: Int, b :: String}
@@ -0,0 +1,15 @@+module Format where+import Data.List++import Prelude+import Data.Int+foo :: Int -> Int+foo 3 = 2+foo x = x+bar :: String -> IO String+bar s = do+ x <- return "hello"+ return "asdf"++data Baz = Baz { a :: Int, b :: String }+
@@ -0,0 +1,16 @@+module Format where++import Data.Int+import Data.List+import Prelude++foo :: Int -> Int+foo 3 = 2+foo x = x++bar :: String -> IO String+bar s = do+ x <- return "hello"+ return "asdf"++data Baz = Baz {a :: Int, b :: String}
@@ -0,0 +1,16 @@+module Format where++import Data.Int+import Data.List+import Prelude++foo :: Int -> Int+foo 3 = 2+foo x = x++bar :: String -> IO String+bar s = do+ x <- return "hello"+ return "asdf"++data Baz = Baz {a :: Int, b :: String}
@@ -0,0 +1,5 @@+import Data.Bool+import Data.Char+import Data.Data+import Data.Either+import Data.Int
@@ -0,0 +1,5 @@+import Data.Char+import Data.Either+import Data.Int+import Data.Data+import Data.Bool
@@ -0,0 +1,5 @@+import Data.Bool+import Data.Char+import Data.Data+import Data.Either+import Data.Int
@@ -0,0 +1,6 @@+cradle:+ direct:+ arguments:+ - "-i src/"+ - "Lib"+ - "Lib2"
@@ -0,0 +1,40 @@+module Lib++ where++someFunc :: IO ()+someFunc = putStrLn "someFunc"++data DataType = DataType Int++dataTypeId :: DataType -> DataType+dataTypeId dataType = dataType++newtype NewType = NewType Int++newTypeId :: NewType -> NewType+newTypeId newType = newType++data Enu = First | Second++enuId :: Enu -> Enu+enuId enu = enu++toNum :: Enu -> Int+toNum First = 1+toNum Second = 2++type MyInt = Int++myIntId :: MyInt -> MyInt+myIntId myInt = myInt++type TypEnu = Enu++typEnuId :: TypEnu -> TypEnu+typEnuId enu = enu++data Parameter a = Parameter a++parameterId :: Parameter a -> Parameter a+parameterId pid = pid
@@ -0,0 +1,13 @@+module Lib2 where++import Lib++g = do+ someFunc+ print x+ where z = 1+2+ y = z+z+ x = y*z++otherId :: DataType -> DataType+otherId dataType = dataType
@@ -0,0 +1,11 @@+cradle:+ direct:+ arguments:+ - "CodeActionImport"+ - "CodeActionOnly"+ - "CodeActionRename"+ - "Highlight"+ - "Symbols"+ - "TopLevelSignature"+ - "TypedHoles"+ - "TypedHoles2"
@@ -0,0 +1,1 @@+main = putStrLn "hey"
@@ -0,0 +1,4 @@+module Main where++main :: IO ()+main = putStrLn "Hello, Haskell!"
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
@@ -0,0 +1,8 @@+cabal-version: >=1.10+name: hieBiosMainIs+version: 0.1.0.0+build-type: Simple+executable hieBiosMainIs+ main-is: Main.hs+ build-depends: base >=4.12 && <4.13+ default-language: Haskell2010
@@ -0,0 +1,5 @@+{-# LANGUAGE LambdaCase #-}+module ApplyRefact1 where++f = \case "true" -> (True)+ _ -> False
@@ -0,0 +1,2 @@+main = undefined+foo x = id x
@@ -0,0 +1,8 @@+{-# LANGUAGE CPP #-}+module ApplyRefact3 where++#ifdef FLAG+f = (1)+#else+g = 2+#endif
@@ -0,0 +1,5 @@+module ApplyRefact4 where++{-# ANN module "HLint: ignore Redundant bracket" #-}+f = (1)+
@@ -0,0 +1,7 @@+module ApplyRefact5 where++{- HLINT ignore "Redundant bracket" -}+f = (1)++{-# HLINT ignore "Use camelCase" #-}+camel_case = undefined
@@ -0,0 +1,11 @@+-- comment before header+module ApplyRefact6 where++{-# standalone annotation #-}++-- standalone comment++-- | haddock comment+f = {- inline comment -} ({- inline comment inside refactored code -}1) -- ending comment++-- final comment
@@ -0,0 +1,9 @@+module ApplyRefact2 where++#include "test.h"++#ifdef TEST+f = (1)+#else+f = 1+#endif
@@ -0,0 +1,7 @@+module ApplyRefact3 where++#ifdef FLAG+f = (1)+#else+g = 2+#endif
@@ -0,0 +1,7 @@+cradle:+ direct:+ arguments:+ - "-XCPP"+ - "-DFLAG"+ - "ApplyRefact3"+ - "ApplyRefact2"
@@ -0,0 +1,1 @@+#define TEST
@@ -0,0 +1,11 @@+cradle:+ direct:+ arguments:+ - "-DFLAG"+ - "-Wno-unrecognised-pragmas"+ - "ApplyRefact1"+ - "ApplyRefact2"+ - "ApplyRefact3"+ - "ApplyRefact4"+ - "ApplyRefact5"+ - "ApplyRefact6"
@@ -0,0 +1,2 @@+- ignore: { name: "Redundant bracket" }+- ignore: { name: "Use camelCase" }
@@ -0,0 +1,5 @@+module ApplyRefact where++f = (1)++camel_case = undefined
@@ -0,0 +1,4 @@+cradle:+ direct:+ arguments:+ - "ApplyRefact"
@@ -0,0 +1,4 @@+module ApplyRefact1 where++f = \case "true" -> (True)+ _ -> False
@@ -0,0 +1,5 @@+cradle:+ direct:+ arguments:+ - "-XLambdaCase"+ - "ApplyRefact1"
@@ -0,0 +1,3 @@+module ApplyRefact1 where++a = (id @Int 1)
@@ -0,0 +1,5 @@+cradle:+ direct:+ arguments:+ - "-XTypeApplications"+ - "ApplyRefact1"
@@ -0,0 +1,41 @@+module Main where++{-@ type Even = {v:Int | v mod 2 = 0} @-}++{-@ weAreEven :: [Even] @-}+weAreEven = [(0-10), (0-4), 0, 2, 666]++{-@ notEven :: Even @-}+notEven = 7++{-@ isEven :: n:Nat -> {v:Bool | (v <=> (n mod 2 == 0))} @-}+isEven :: Int -> Bool+isEven 0 = True+isEven 1 = False+isEven n = not (isEven (n-1))++{-@ evens :: n:Nat -> [Even] @-}+evens n = [i | i <- range 0 n, isEven i]++{-@ range :: lo:Int -> hi:Int -> [{v:Int | (lo <= v && v < hi)}] / [hi -lo] @-}+range lo hi+ | lo < hi = lo : range (lo+1) hi+ | otherwise = []++{-@ shift :: [Even] -> Even -> [Even] @-}+shift xs k = [x + k | x <- xs]++{-@ double :: [Nat] -> [Even] @-}+double xs = [x + x | x <- xs]++++---++notEven :: Int+weAreEven :: [Int]+shift :: [Int] -> Int -> [Int]+double :: [Int] -> [Int]+range :: Int -> Int -> [Int]++main = putStrLn "hello"
@@ -0,0 +1,2 @@++
@@ -0,0 +1,3 @@+module TEmptyModule where++
@@ -0,0 +1,7 @@+module BadName+ ( x+ )+where++x :: Integer+x = 11
@@ -0,0 +1,7 @@+module TWrongModuleName+ ( x+ )+where++x :: Integer+x = 11
@@ -0,0 +1,1 @@+cradle: { direct: { arguments: ["TEmptyModule", "TWrongModuleName", "mainlike"] } }
@@ -0,0 +1,1 @@+module Main where
@@ -0,0 +1,5 @@+cradle:+ direct:+ arguments:+ - "src/CodeActionRedundant"+ - "src/MultipleImports"
@@ -0,0 +1,5 @@+{-# OPTIONS_GHC -Wunused-imports #-}+module CodeActionRedundant where+import Data.List+main :: IO ()+main = putStrLn "hello"
@@ -0,0 +1,6 @@+{-# OPTIONS_GHC -Wunused-imports #-}+module MultipleImports where+import Data.Foldable+import Data.Maybe+foo :: Int+foo = fromJust (Just 3)
@@ -0,0 +1,18 @@+name: test+version: 0.1.0.0+-- synopsis:+-- description:+license: BSD3+author: Author name here+maintainer: example@example.com+copyright: 2017 Author name here+category: Web+build-type: Simple+cabal-version: >=1.10++library+ exposed-modules: CodeActionRedundant, MultipleImports+ hs-source-dirs: src+ build-depends: base >= 4.7 && < 5+ default-language: Haskell2010+ ghc-options: -Wall -fwarn-unused-imports
@@ -0,0 +1,6 @@+main = do+ x <- return $ foo 42+ return (foo x)+foo :: Int -> Int+foo x = x + 1+bar = (+ 1) . foo
@@ -0,0 +1,37 @@+name: testdata+version: 0.1.0.0+cabal-version: >=2.0+build-type: Simple++executable codeactionrename+ build-depends: base+ main-is: CodeActionRename.hs+ default-language: Haskell2010++executable codeactiononly+ build-depends: base+ main-is: CodeActionOnly.hs+ default-language: Haskell2010++++executable hover+ build-depends: base+ main-is: Hover.hs+ default-language: Haskell2010++executable symbols+ build-depends: base+ main-is: Symbols.hs+ default-language: Haskell2010++executable functests+ build-depends: base+ main-is: FuncTest.hs+ default-language: Haskell2010++executable evens+ build-depends: base+ main-is: Evens.hs+ hs-source-dirs: liquid+ default-language: Haskell2010
@@ -0,0 +1,1 @@+packages: test.cabal
@@ -0,0 +1,50 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE NoRebindableSyntax #-}+{-# OPTIONS_GHC -fno-warn-missing-import-lists #-}+module Paths_test (+ version,+ getBinDir, getLibDir, getDynLibDir, getDataDir, getLibexecDir,+ getDataFileName, getSysconfDir+ ) where++import qualified Control.Exception as Exception+import Data.Version (Version(..))+import System.Environment (getEnv)+import Prelude++#if defined(VERSION_base)++#if MIN_VERSION_base(4,0,0)+catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a+#else+catchIO :: IO a -> (Exception.Exception -> IO a) -> IO a+#endif++#else+catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a+#endif+catchIO = Exception.catch++version :: Version+version = Version [0,1,0,0] []+bindir, libdir, dynlibdir, datadir, libexecdir, sysconfdir :: FilePath++bindir = "/home/berberman/.cabal/bin"+libdir = "/home/berberman/.cabal/lib/x86_64-linux-ghc-8.10.2/test-0.1.0.0-inplace"+dynlibdir = "/home/berberman/.cabal/lib/x86_64-linux-ghc-8.10.2"+datadir = "/home/berberman/.cabal/share/x86_64-linux-ghc-8.10.2/test-0.1.0.0"+libexecdir = "/home/berberman/.cabal/libexec/x86_64-linux-ghc-8.10.2/test-0.1.0.0"+sysconfdir = "/home/berberman/.cabal/etc"++getBinDir, getLibDir, getDynLibDir, getDataDir, getLibexecDir, getSysconfDir :: IO FilePath+getBinDir = catchIO (getEnv "test_bindir") (\_ -> return bindir)+getLibDir = catchIO (getEnv "test_libdir") (\_ -> return libdir)+getDynLibDir = catchIO (getEnv "test_dynlibdir") (\_ -> return dynlibdir)+getDataDir = catchIO (getEnv "test_datadir") (\_ -> return datadir)+getLibexecDir = catchIO (getEnv "test_libexecdir") (\_ -> return libexecdir)+getSysconfDir = catchIO (getEnv "test_sysconfdir") (\_ -> return sysconfdir)++getDataFileName :: FilePath -> IO FilePath+getDataFileName name = do+ dir <- getDataDir+ return (dir ++ "/" ++ name)
@@ -0,0 +1,143 @@+/* DO NOT EDIT: This file is automatically generated by Cabal */++/* package test-0.1.0.0 */+#ifndef VERSION_test+#define VERSION_test "0.1.0.0"+#endif /* VERSION_test */+#ifndef MIN_VERSION_test+#define MIN_VERSION_test(major1,major2,minor) (\+ (major1) < 0 || \+ (major1) == 0 && (major2) < 1 || \+ (major1) == 0 && (major2) == 1 && (minor) <= 0)+#endif /* MIN_VERSION_test */++/* package base-4.14.1.0 */+#ifndef VERSION_base+#define VERSION_base "4.14.1.0"+#endif /* VERSION_base */+#ifndef MIN_VERSION_base+#define MIN_VERSION_base(major1,major2,minor) (\+ (major1) < 4 || \+ (major1) == 4 && (major2) < 14 || \+ (major1) == 4 && (major2) == 14 && (minor) <= 1)+#endif /* MIN_VERSION_base */++/* tool cpphs-1.20.9 */+#ifndef TOOL_VERSION_cpphs+#define TOOL_VERSION_cpphs "1.20.9"+#endif /* TOOL_VERSION_cpphs */+#ifndef MIN_TOOL_VERSION_cpphs+#define MIN_TOOL_VERSION_cpphs(major1,major2,minor) (\+ (major1) < 1 || \+ (major1) == 1 && (major2) < 20 || \+ (major1) == 1 && (major2) == 20 && (minor) <= 9)+#endif /* MIN_TOOL_VERSION_cpphs */++/* tool gcc-9.3.0 */+#ifndef TOOL_VERSION_gcc+#define TOOL_VERSION_gcc "9.3.0"+#endif /* TOOL_VERSION_gcc */+#ifndef MIN_TOOL_VERSION_gcc+#define MIN_TOOL_VERSION_gcc(major1,major2,minor) (\+ (major1) < 9 || \+ (major1) == 9 && (major2) < 3 || \+ (major1) == 9 && (major2) == 3 && (minor) <= 0)+#endif /* MIN_TOOL_VERSION_gcc */++/* tool ghc-8.10.2 */+#ifndef TOOL_VERSION_ghc+#define TOOL_VERSION_ghc "8.10.2"+#endif /* TOOL_VERSION_ghc */+#ifndef MIN_TOOL_VERSION_ghc+#define MIN_TOOL_VERSION_ghc(major1,major2,minor) (\+ (major1) < 8 || \+ (major1) == 8 && (major2) < 10 || \+ (major1) == 8 && (major2) == 10 && (minor) <= 2)+#endif /* MIN_TOOL_VERSION_ghc */++/* tool ghc-pkg-8.10.2 */+#ifndef TOOL_VERSION_ghc_pkg+#define TOOL_VERSION_ghc_pkg "8.10.2"+#endif /* TOOL_VERSION_ghc_pkg */+#ifndef MIN_TOOL_VERSION_ghc_pkg+#define MIN_TOOL_VERSION_ghc_pkg(major1,major2,minor) (\+ (major1) < 8 || \+ (major1) == 8 && (major2) < 10 || \+ (major1) == 8 && (major2) == 10 && (minor) <= 2)+#endif /* MIN_TOOL_VERSION_ghc_pkg */++/* tool haddock-2.24.0 */+#ifndef TOOL_VERSION_haddock+#define TOOL_VERSION_haddock "2.24.0"+#endif /* TOOL_VERSION_haddock */+#ifndef MIN_TOOL_VERSION_haddock+#define MIN_TOOL_VERSION_haddock(major1,major2,minor) (\+ (major1) < 2 || \+ (major1) == 2 && (major2) < 24 || \+ (major1) == 2 && (major2) == 24 && (minor) <= 0)+#endif /* MIN_TOOL_VERSION_haddock */++/* tool hpc-0.68 */+#ifndef TOOL_VERSION_hpc+#define TOOL_VERSION_hpc "0.68"+#endif /* TOOL_VERSION_hpc */+#ifndef MIN_TOOL_VERSION_hpc+#define MIN_TOOL_VERSION_hpc(major1,major2,minor) (\+ (major1) < 0 || \+ (major1) == 0 && (major2) < 68 || \+ (major1) == 0 && (major2) == 68 && (minor) <= 0)+#endif /* MIN_TOOL_VERSION_hpc */++/* tool hsc2hs-0.68.7 */+#ifndef TOOL_VERSION_hsc2hs+#define TOOL_VERSION_hsc2hs "0.68.7"+#endif /* TOOL_VERSION_hsc2hs */+#ifndef MIN_TOOL_VERSION_hsc2hs+#define MIN_TOOL_VERSION_hsc2hs(major1,major2,minor) (\+ (major1) < 0 || \+ (major1) == 0 && (major2) < 68 || \+ (major1) == 0 && (major2) == 68 && (minor) <= 7)+#endif /* MIN_TOOL_VERSION_hsc2hs */++/* tool hscolour-1.24 */+#ifndef TOOL_VERSION_hscolour+#define TOOL_VERSION_hscolour "1.24"+#endif /* TOOL_VERSION_hscolour */+#ifndef MIN_TOOL_VERSION_hscolour+#define MIN_TOOL_VERSION_hscolour(major1,major2,minor) (\+ (major1) < 1 || \+ (major1) == 1 && (major2) < 24 || \+ (major1) == 1 && (major2) == 24 && (minor) <= 0)+#endif /* MIN_TOOL_VERSION_hscolour */++/* tool runghc-8.10.2 */+#ifndef TOOL_VERSION_runghc+#define TOOL_VERSION_runghc "8.10.2"+#endif /* TOOL_VERSION_runghc */+#ifndef MIN_TOOL_VERSION_runghc+#define MIN_TOOL_VERSION_runghc(major1,major2,minor) (\+ (major1) < 8 || \+ (major1) == 8 && (major2) < 10 || \+ (major1) == 8 && (major2) == 10 && (minor) <= 2)+#endif /* MIN_TOOL_VERSION_runghc */++/* tool strip-2.31 */+#ifndef TOOL_VERSION_strip+#define TOOL_VERSION_strip "2.31"+#endif /* TOOL_VERSION_strip */+#ifndef MIN_TOOL_VERSION_strip+#define MIN_TOOL_VERSION_strip(major1,major2,minor) (\+ (major1) < 2 || \+ (major1) == 2 && (major2) < 31 || \+ (major1) == 2 && (major2) == 31 && (minor) <= 0)+#endif /* MIN_TOOL_VERSION_strip */++#ifndef CURRENT_PACKAGE_KEY+#define CURRENT_PACKAGE_KEY "test-0.1.0.0-inplace"+#endif /* CURRENT_PACKAGE_KEY */+#ifndef CURRENT_COMPONENT_ID+#define CURRENT_COMPONENT_ID "test-0.1.0.0-inplace"+#endif /* CURRENT_COMPONENT_ID */+#ifndef CURRENT_PACKAGE_VERSION+#define CURRENT_PACKAGE_VERSION "0.1.0.0"+#endif /* CURRENT_PACKAGE_VERSION */
@@ -0,0 +1,50 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE NoRebindableSyntax #-}+{-# OPTIONS_GHC -fno-warn-missing-import-lists #-}+module Paths_test (+ version,+ getBinDir, getLibDir, getDynLibDir, getDataDir, getLibexecDir,+ getDataFileName, getSysconfDir+ ) where++import qualified Control.Exception as Exception+import Data.Version (Version(..))+import System.Environment (getEnv)+import Prelude++#if defined(VERSION_base)++#if MIN_VERSION_base(4,0,0)+catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a+#else+catchIO :: IO a -> (Exception.Exception -> IO a) -> IO a+#endif++#else+catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a+#endif+catchIO = Exception.catch++version :: Version+version = Version [0,1,0,0] []+bindir, libdir, dynlibdir, datadir, libexecdir, sysconfdir :: FilePath++bindir = "/home/berberman/.cabal/bin"+libdir = "/home/berberman/.cabal/lib/x86_64-linux-ghc-8.10.3/test-0.1.0.0-inplace"+dynlibdir = "/home/berberman/.cabal/lib/x86_64-linux-ghc-8.10.3"+datadir = "/home/berberman/.cabal/share/x86_64-linux-ghc-8.10.3/test-0.1.0.0"+libexecdir = "/home/berberman/.cabal/libexec/x86_64-linux-ghc-8.10.3/test-0.1.0.0"+sysconfdir = "/home/berberman/.cabal/etc"++getBinDir, getLibDir, getDynLibDir, getDataDir, getLibexecDir, getSysconfDir :: IO FilePath+getBinDir = catchIO (getEnv "test_bindir") (\_ -> return bindir)+getLibDir = catchIO (getEnv "test_libdir") (\_ -> return libdir)+getDynLibDir = catchIO (getEnv "test_dynlibdir") (\_ -> return dynlibdir)+getDataDir = catchIO (getEnv "test_datadir") (\_ -> return datadir)+getLibexecDir = catchIO (getEnv "test_libexecdir") (\_ -> return libexecdir)+getSysconfDir = catchIO (getEnv "test_sysconfdir") (\_ -> return sysconfdir)++getDataFileName :: FilePath -> IO FilePath+getDataFileName name = do+ dir <- getDataDir+ return (dir ++ "/" ++ name)
@@ -0,0 +1,143 @@+/* DO NOT EDIT: This file is automatically generated by Cabal */++/* package test-0.1.0.0 */+#ifndef VERSION_test+#define VERSION_test "0.1.0.0"+#endif /* VERSION_test */+#ifndef MIN_VERSION_test+#define MIN_VERSION_test(major1,major2,minor) (\+ (major1) < 0 || \+ (major1) == 0 && (major2) < 1 || \+ (major1) == 0 && (major2) == 1 && (minor) <= 0)+#endif /* MIN_VERSION_test */++/* package base-4.14.1.0 */+#ifndef VERSION_base+#define VERSION_base "4.14.1.0"+#endif /* VERSION_base */+#ifndef MIN_VERSION_base+#define MIN_VERSION_base(major1,major2,minor) (\+ (major1) < 4 || \+ (major1) == 4 && (major2) < 14 || \+ (major1) == 4 && (major2) == 14 && (minor) <= 1)+#endif /* MIN_VERSION_base */++/* tool cpphs-1.20.9 */+#ifndef TOOL_VERSION_cpphs+#define TOOL_VERSION_cpphs "1.20.9"+#endif /* TOOL_VERSION_cpphs */+#ifndef MIN_TOOL_VERSION_cpphs+#define MIN_TOOL_VERSION_cpphs(major1,major2,minor) (\+ (major1) < 1 || \+ (major1) == 1 && (major2) < 20 || \+ (major1) == 1 && (major2) == 20 && (minor) <= 9)+#endif /* MIN_TOOL_VERSION_cpphs */++/* tool gcc-10.2.0 */+#ifndef TOOL_VERSION_gcc+#define TOOL_VERSION_gcc "10.2.0"+#endif /* TOOL_VERSION_gcc */+#ifndef MIN_TOOL_VERSION_gcc+#define MIN_TOOL_VERSION_gcc(major1,major2,minor) (\+ (major1) < 10 || \+ (major1) == 10 && (major2) < 2 || \+ (major1) == 10 && (major2) == 2 && (minor) <= 0)+#endif /* MIN_TOOL_VERSION_gcc */++/* tool ghc-8.10.3 */+#ifndef TOOL_VERSION_ghc+#define TOOL_VERSION_ghc "8.10.3"+#endif /* TOOL_VERSION_ghc */+#ifndef MIN_TOOL_VERSION_ghc+#define MIN_TOOL_VERSION_ghc(major1,major2,minor) (\+ (major1) < 8 || \+ (major1) == 8 && (major2) < 10 || \+ (major1) == 8 && (major2) == 10 && (minor) <= 3)+#endif /* MIN_TOOL_VERSION_ghc */++/* tool ghc-pkg-8.10.3 */+#ifndef TOOL_VERSION_ghc_pkg+#define TOOL_VERSION_ghc_pkg "8.10.3"+#endif /* TOOL_VERSION_ghc_pkg */+#ifndef MIN_TOOL_VERSION_ghc_pkg+#define MIN_TOOL_VERSION_ghc_pkg(major1,major2,minor) (\+ (major1) < 8 || \+ (major1) == 8 && (major2) < 10 || \+ (major1) == 8 && (major2) == 10 && (minor) <= 3)+#endif /* MIN_TOOL_VERSION_ghc_pkg */++/* tool haddock-2.24.0 */+#ifndef TOOL_VERSION_haddock+#define TOOL_VERSION_haddock "2.24.0"+#endif /* TOOL_VERSION_haddock */+#ifndef MIN_TOOL_VERSION_haddock+#define MIN_TOOL_VERSION_haddock(major1,major2,minor) (\+ (major1) < 2 || \+ (major1) == 2 && (major2) < 24 || \+ (major1) == 2 && (major2) == 24 && (minor) <= 0)+#endif /* MIN_TOOL_VERSION_haddock */++/* tool hpc-0.68 */+#ifndef TOOL_VERSION_hpc+#define TOOL_VERSION_hpc "0.68"+#endif /* TOOL_VERSION_hpc */+#ifndef MIN_TOOL_VERSION_hpc+#define MIN_TOOL_VERSION_hpc(major1,major2,minor) (\+ (major1) < 0 || \+ (major1) == 0 && (major2) < 68 || \+ (major1) == 0 && (major2) == 68 && (minor) <= 0)+#endif /* MIN_TOOL_VERSION_hpc */++/* tool hsc2hs-0.68.7 */+#ifndef TOOL_VERSION_hsc2hs+#define TOOL_VERSION_hsc2hs "0.68.7"+#endif /* TOOL_VERSION_hsc2hs */+#ifndef MIN_TOOL_VERSION_hsc2hs+#define MIN_TOOL_VERSION_hsc2hs(major1,major2,minor) (\+ (major1) < 0 || \+ (major1) == 0 && (major2) < 68 || \+ (major1) == 0 && (major2) == 68 && (minor) <= 7)+#endif /* MIN_TOOL_VERSION_hsc2hs */++/* tool hscolour-1.24 */+#ifndef TOOL_VERSION_hscolour+#define TOOL_VERSION_hscolour "1.24"+#endif /* TOOL_VERSION_hscolour */+#ifndef MIN_TOOL_VERSION_hscolour+#define MIN_TOOL_VERSION_hscolour(major1,major2,minor) (\+ (major1) < 1 || \+ (major1) == 1 && (major2) < 24 || \+ (major1) == 1 && (major2) == 24 && (minor) <= 0)+#endif /* MIN_TOOL_VERSION_hscolour */++/* tool runghc-8.10.3 */+#ifndef TOOL_VERSION_runghc+#define TOOL_VERSION_runghc "8.10.3"+#endif /* TOOL_VERSION_runghc */+#ifndef MIN_TOOL_VERSION_runghc+#define MIN_TOOL_VERSION_runghc(major1,major2,minor) (\+ (major1) < 8 || \+ (major1) == 8 && (major2) < 10 || \+ (major1) == 8 && (major2) == 10 && (minor) <= 3)+#endif /* MIN_TOOL_VERSION_runghc */++/* tool strip-2.34 */+#ifndef TOOL_VERSION_strip+#define TOOL_VERSION_strip "2.34"+#endif /* TOOL_VERSION_strip */+#ifndef MIN_TOOL_VERSION_strip+#define MIN_TOOL_VERSION_strip(major1,major2,minor) (\+ (major1) < 2 || \+ (major1) == 2 && (major2) < 34 || \+ (major1) == 2 && (major2) == 34 && (minor) <= 0)+#endif /* MIN_TOOL_VERSION_strip */++#ifndef CURRENT_PACKAGE_KEY+#define CURRENT_PACKAGE_KEY "test-0.1.0.0-inplace"+#endif /* CURRENT_PACKAGE_KEY */+#ifndef CURRENT_COMPONENT_ID+#define CURRENT_COMPONENT_ID "test-0.1.0.0-inplace"+#endif /* CURRENT_COMPONENT_ID */+#ifndef CURRENT_PACKAGE_VERSION+#define CURRENT_PACKAGE_VERSION "0.1.0.0"+#endif /* CURRENT_PACKAGE_VERSION */
@@ -0,0 +1,4 @@+cradle:+ cabal:+ - path: "src"+ component: "lib:test"
@@ -0,0 +1,2 @@+module WError where+main = undefined
@@ -0,0 +1,18 @@+name: test+version: 0.1.0.0+-- synopsis:+-- description:+license: BSD3+author: Author name here+maintainer: example@example.com+copyright: 2017 Author name here+category: Web+build-type: Simple+cabal-version: >=1.10++library+ exposed-modules: WError+ hs-source-dirs: src+ build-depends: base >= 4.7 && < 5+ default-language: Haskell2010+ ghc-options: -Wall -Werror
@@ -0,0 +1,32 @@+module Test.Hls.Command+ ( hlsCommand,+ hlsCommandExamplePlugin,+ hlsCommandVomit,+ logFilePath,+ )+where++import Data.Maybe (fromMaybe)+import System.Environment (lookupEnv)+import System.IO.Unsafe (unsafePerformIO)+import Test.Hls++logFilePath :: String+logFilePath = "hls-" ++ show ghcVersion ++ ".log"++-- | The command to execute the version of hls for the current compiler.+--+-- Both @stack test@ and @cabal new-test@ setup the environment so @hls@ is+-- on PATH. Cabal seems to respond to @build-tool-depends@ specifically while+-- stack just puts all project executables on PATH.+hlsCommand :: String+{-# NOINLINE hlsCommand #-}+hlsCommand = unsafePerformIO $ do+ testExe <- fromMaybe "haskell-language-server" <$> lookupEnv "HLS_TEST_EXE"+ pure $ testExe ++ " --lsp -d -j2 -l test-logs/" ++ logFilePath++hlsCommandVomit :: String+hlsCommandVomit = hlsCommand ++ " --vomit"++hlsCommandExamplePlugin :: String+hlsCommandExamplePlugin = hlsCommand ++ " --example"
@@ -1,443 +0,0 @@-{-# LANGUAGE CPP, OverloadedStrings, NamedFieldPuns, MultiParamTypeClasses, DuplicateRecordFields, TypeOperators, GADTs #-} -{-# LANGUAGE FlexibleContexts #-} -module Test.Hls.Util - ( - codeActionSupportCaps - , expectCodeAction - , expectDiagnostic - , expectNoMoreDiagnostics - , expectSameLocations - , failIfSessionTimeout - , flushStackEnvironment - , fromAction - , fromCommand - , getHspecFormattedConfig - , ghcVersion, GhcVersion(..) - , hostOS, OS(..) - , matchesCurrentEnv, EnvSpec(..) - , hlsCommand - , hlsCommandExamplePlugin - , hlsCommandVomit - , ignoreForGhcVersions - , ignoreInEnv - , inspectCodeAction - , inspectCommand - , inspectDiagnostic - , knownBrokenOnWindows - , knownBrokenForGhcVersions - , knownBrokenInEnv - , logFilePath - , setupBuildToolFiles - , SymbolLocation - , waitForDiagnosticsFrom - , waitForDiagnosticsFromSource - , waitForDiagnosticsFromSourceWithTimeout - , withCurrentDirectoryInTmp - ) -where - -import qualified Data.Aeson as A -import Control.Exception (throwIO, catch) -import Control.Monad -import Control.Monad.IO.Class -import Control.Applicative.Combinators (skipManyTill, (<|>)) -import Control.Lens ((^.)) -import Data.Default -import Data.List (intercalate) -import Data.List.Extra (find) -import Data.Maybe -import qualified Data.Set as Set -import qualified Data.Text as T -import Language.LSP.Types hiding (Reason(..)) -import qualified Language.LSP.Test as Test -import qualified Language.LSP.Types.Lens as L -import qualified Language.LSP.Types.Capabilities as C -import System.Directory -import System.Environment -import System.Time.Extra (Seconds, sleep) -import System.FilePath -import System.IO.Temp -import System.IO.Unsafe -import Test.Hspec.Runner -import Test.Hspec.Core.Formatters hiding (Seconds) -import Test.Tasty (TestTree) -import Test.Tasty.ExpectedFailure (ignoreTestBecause, expectFailBecause) -import Test.Tasty.HUnit (Assertion, assertFailure, (@?=)) -import Text.Blaze.Renderer.String (renderMarkup) -import Text.Blaze.Internal hiding (null) -import System.Info.Extra (isWindows, isMac) - -codeActionSupportCaps :: C.ClientCapabilities -codeActionSupportCaps = def { C._textDocument = Just textDocumentCaps } - where - textDocumentCaps = def { C._codeAction = Just codeActionCaps } - codeActionCaps = CodeActionClientCapabilities (Just True) (Just literalSupport) (Just True) - literalSupport = CodeActionLiteralSupport def - --- --------------------------------------------------------------------- - -setupBuildToolFiles :: IO () -setupBuildToolFiles = do - forM_ files setupDirectFilesIn - -setupDirectFilesIn :: FilePath -> IO () -setupDirectFilesIn f = - writeFile (f ++ "hie.yaml") hieYamlCradleDirectContents - - --- --------------------------------------------------------------------- - -files :: [FilePath] -files = - [ "./test/testdata/" - -- , "./test/testdata/addPackageTest/cabal-exe/" - -- , "./test/testdata/addPackageTest/hpack-exe/" - -- , "./test/testdata/addPackageTest/cabal-lib/" - -- , "./test/testdata/addPackageTest/hpack-lib/" - -- , "./test/testdata/addPragmas/" - -- , "./test/testdata/badProjects/cabal/" - -- , "./test/testdata/completion/" - -- , "./test/testdata/definition/" - -- , "./test/testdata/gototest/" - -- , "./test/testdata/redundantImportTest/" - -- , "./test/testdata/wErrorTest/" - ] - -data GhcVersion - = GHC810 - | GHC88 - | GHC86 - | GHC84 - deriving (Eq,Show) - -ghcVersion :: GhcVersion -#if (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(8,10,0,0))) -ghcVersion = GHC810 -#elif (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(8,8,0,0))) -ghcVersion = GHC88 -#elif (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(8,6,0,0))) -ghcVersion = GHC86 -#elif (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(8,4,0,0))) -ghcVersion = GHC84 -#endif - -data EnvSpec = HostOS OS | GhcVer GhcVersion - deriving (Show, Eq) - -matchesCurrentEnv :: EnvSpec -> Bool -matchesCurrentEnv (HostOS os) = hostOS == os -matchesCurrentEnv (GhcVer ver) = ghcVersion == ver - -data OS = Windows | MacOS | Linux - deriving (Show, Eq) - -hostOS :: OS -hostOS - | isWindows = Windows - | isMac = MacOS - | otherwise = Linux - --- | Mark as broken if /any/ of environmental spec mathces the current environment. -knownBrokenInEnv :: [EnvSpec] -> String -> TestTree -> TestTree -knownBrokenInEnv envSpecs reason - | any matchesCurrentEnv envSpecs = expectFailBecause reason - | otherwise = id - -knownBrokenOnWindows :: String -> TestTree -> TestTree -knownBrokenOnWindows reason - | isWindows = expectFailBecause reason - | otherwise = id - -knownBrokenForGhcVersions :: [GhcVersion] -> String -> TestTree -> TestTree -knownBrokenForGhcVersions vers reason - | ghcVersion `elem` vers = expectFailBecause reason - | otherwise = id - --- | IgnroeTest if /any/ of environmental spec mathces the current environment. -ignoreInEnv :: [EnvSpec] -> String -> TestTree -> TestTree -ignoreInEnv envSpecs reason - | any matchesCurrentEnv envSpecs = ignoreTestBecause reason - | otherwise = id - -ignoreForGhcVersions :: [GhcVersion] -> String -> TestTree -> TestTree -ignoreForGhcVersions vers reason - | ghcVersion `elem` vers = ignoreTestBecause reason - | otherwise = id - -logFilePath :: String -logFilePath = "hls-" ++ show ghcVersion ++ ".log" - --- | The command to execute the version of hls for the current compiler. --- --- Both @stack test@ and @cabal new-test@ setup the environment so @hls@ is --- on PATH. Cabal seems to respond to @build-tool-depends@ specifically while --- stack just puts all project executables on PATH. -hlsCommand :: String -{-# NOINLINE hlsCommand #-} -hlsCommand = unsafePerformIO $ do - testExe <- fromMaybe "haskell-language-server" <$> lookupEnv "HLS_TEST_EXE" - pure $ testExe ++ " --lsp -d -j2 -l test-logs/" ++ logFilePath - -hlsCommandVomit :: String -hlsCommandVomit = hlsCommand ++ " --vomit" - -hlsCommandExamplePlugin :: String -hlsCommandExamplePlugin = hlsCommand ++ " --example" - --- --------------------------------------------------------------------- - -hieYamlCradleDirectContents :: String -hieYamlCradleDirectContents = unlines - [ "# WARNING: THIS FILE IS AUTOGENERATED IN test/utils/TestUtils.hs. IT WILL BE OVERWRITTEN ON EVERY TEST RUN" - , "cradle:" - , " direct:" - , " arguments:" - , " - -i." - ] - - --- --------------------------------------------------------------------- - -getHspecFormattedConfig :: String -> IO Config -getHspecFormattedConfig name = do - -- https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables - isCI <- isJust <$> lookupEnv "CI" - - -- Only use the xml formatter on CI since it hides console output - if isCI - then do - let subdir = "test-results" </> name - createDirectoryIfMissing True subdir - - return $ defaultConfig { configFormatter = Just xmlFormatter - , configOutputFile = Right $ subdir </> "results.xml" - } - else return defaultConfig - --- | A Hspec formatter for CircleCI. --- Originally from https://github.com/LeastAuthority/hspec-jenkins -xmlFormatter :: Formatter -xmlFormatter = silent { - headerFormatter = do - writeLine "<?xml version='1.0' encoding='UTF-8'?>" - writeLine "<testsuite>" - , exampleSucceeded - , exampleFailed - , examplePending - , footerFormatter = writeLine "</testsuite>" - } - where - -#if MIN_VERSION_hspec(2,5,0) - exampleSucceeded path _ = -#else - exampleSucceeded path = -#endif - writeLine $ renderMarkup $ testcase path "" - -#if MIN_VERSION_hspec(2,5,0) - exampleFailed path _ err = -#else - exampleFailed path (Left err) = - writeLine $ renderMarkup $ testcase path $ - failure ! message (show err) $ "" - exampleFailed path (Right err) = -#endif - writeLine $ renderMarkup $ testcase path $ - failure ! message (reasonAsString err) $ "" - -#if MIN_VERSION_hspec(2,5,0) - examplePending path _ reason = -#else - examplePending path reason = -#endif - writeLine $ renderMarkup $ testcase path $ - case reason of - Just desc -> skipped ! message desc $ "" - Nothing -> skipped "" - - failure, skipped :: Markup -> Markup - failure = customParent "failure" - skipped = customParent "skipped" - - name, className, message :: String -> Attribute - name = customAttribute "name" . stringValue - className = customAttribute "classname" . stringValue - message = customAttribute "message" . stringValue - - testcase :: Path -> Markup -> Markup - testcase (xs,x) = customParent "testcase" ! name x ! className (intercalate "." xs) - - reasonAsString :: FailureReason -> String - reasonAsString NoReason = "no reason given" - reasonAsString (Reason x) = x - reasonAsString (ExpectedButGot Nothing expected got) = "Expected " ++ expected ++ " but got " ++ got - reasonAsString (ExpectedButGot (Just src) expected got) = src ++ " expected " ++ expected ++ " but got " ++ got -#if MIN_VERSION_hspec(2,5,0) - reasonAsString (Error Nothing err ) = show err - reasonAsString (Error (Just s) err) = s ++ show err -#endif - --- --------------------------------------------------------------------- - -flushStackEnvironment :: IO () -flushStackEnvironment = do - -- We need to clear these environment variables to prevent - -- collisions with stack usages - -- See https://github.com/commercialhaskell/stack/issues/4875 - unsetEnv "GHC_PACKAGE_PATH" - unsetEnv "GHC_ENVIRONMENT" - unsetEnv "HASKELL_PACKAGE_SANDBOX" - unsetEnv "HASKELL_PACKAGE_SANDBOXES" - --- --------------------------------------------------------------------- - --- | Like 'withCurrentDirectory', but will copy the directory over to the system --- temporary directory first to avoid haskell-language-server's source tree from --- interfering with the cradle -withCurrentDirectoryInTmp :: FilePath -> IO a -> IO a -withCurrentDirectoryInTmp dir f = - withTempCopy dir $ \newDir -> - withCurrentDirectory newDir f - -withTempCopy :: FilePath -> (FilePath -> IO a) -> IO a -withTempCopy srcDir f = do - withSystemTempDirectory "hls-test" $ \newDir -> do - copyDir srcDir newDir - f newDir - -copyDir :: FilePath -> FilePath -> IO () -copyDir src dst = do - cnts <- listDirectory src - forM_ cnts $ \file -> do - unless (file `elem` ignored) $ do - let srcFp = src </> file - dstFp = dst </> file - isDir <- doesDirectoryExist srcFp - if isDir - then createDirectory dstFp >> copyDir srcFp dstFp - else copyFile srcFp dstFp - where ignored = ["dist", "dist-newstyle", ".stack-work"] - -fromAction :: (Command |? CodeAction) -> CodeAction -fromAction (InR action) = action -fromAction _ = error "Not a code action" - -fromCommand :: (Command |? CodeAction) -> Command -fromCommand (InL command) = command -fromCommand _ = error "Not a command" - -onMatch :: [a] -> (a -> Bool) -> String -> IO a -onMatch as predicate err = maybe (fail err) return (find predicate as) - -inspectDiagnostic :: [Diagnostic] -> [T.Text] -> IO Diagnostic -inspectDiagnostic diags s = onMatch diags (\ca -> all (`T.isInfixOf` (ca ^. L.message)) s) err - where err = "expected diagnostic matching '" ++ show s ++ "' but did not find one" - -expectDiagnostic :: [Diagnostic] -> [T.Text] -> IO () -expectDiagnostic diags s = void $ inspectDiagnostic diags s - -inspectCodeAction :: [Command |? CodeAction] -> [T.Text] -> IO CodeAction -inspectCodeAction cars s = fromAction <$> onMatch cars predicate err - where predicate (InR ca) = all (`T.isInfixOf` (ca ^. L.title)) s - predicate _ = False - err = "expected code action matching '" ++ show s ++ "' but did not find one" - -expectCodeAction :: [Command |? CodeAction] -> [T.Text] -> IO () -expectCodeAction cars s = void $ inspectCodeAction cars s - -inspectCommand :: [Command |? CodeAction] -> [T.Text] -> IO Command -inspectCommand cars s = fromCommand <$> onMatch cars predicate err - where predicate (InL command) = all (`T.isInfixOf` (command ^. L.title)) s - predicate _ = False - err = "expected code action matching '" ++ show s ++ "' but did not find one" - -waitForDiagnosticsFrom :: TextDocumentIdentifier -> Test.Session [Diagnostic] -waitForDiagnosticsFrom doc = do - diagsNot <- skipManyTill Test.anyMessage (Test.message STextDocumentPublishDiagnostics) - let (List diags) = diagsNot ^. L.params . L.diagnostics - if doc ^. L.uri /= diagsNot ^. L.params . L.uri - then waitForDiagnosticsFrom doc - else return diags - -waitForDiagnosticsFromSource :: TextDocumentIdentifier -> String -> Test.Session [Diagnostic] -waitForDiagnosticsFromSource doc src = do - diagsNot <- skipManyTill Test.anyMessage (Test.message STextDocumentPublishDiagnostics) - let (List diags) = diagsNot ^. L.params . L.diagnostics - let res = filter matches diags - if doc ^. L.uri /= diagsNot ^. L.params . L.uri || null res - then waitForDiagnosticsFromSource doc src - else return res - where - matches :: Diagnostic -> Bool - matches d = d ^. L.source == Just (T.pack src) - --- | wait for @timeout@ seconds and report an assertion failure --- if any diagnostic messages arrive in that period -expectNoMoreDiagnostics :: Seconds -> TextDocumentIdentifier -> String -> Test.Session () -expectNoMoreDiagnostics timeout doc src = do - diags <- waitForDiagnosticsFromSourceWithTimeout timeout doc src - unless (null diags) $ - liftIO $ assertFailure $ - "Got unexpected diagnostics for " <> show (doc ^. L.uri) <> - " got " <> show diags - --- | wait for @timeout@ seconds and return diagnostics for the given @document and @source. --- If timeout is 0 it will wait until the session timeout -waitForDiagnosticsFromSourceWithTimeout :: Seconds -> TextDocumentIdentifier -> String -> Test.Session [Diagnostic] -waitForDiagnosticsFromSourceWithTimeout timeout document source = do - when (timeout > 0) $ do - -- Give any further diagnostic messages time to arrive. - liftIO $ sleep timeout - -- Send a dummy message to provoke a response from the server. - -- This guarantees that we have at least one message to - -- process, so message won't block or timeout. - void $ Test.sendNotification (SCustomMethod "non-existent-method") A.Null - handleMessages - where - matches :: Diagnostic -> Bool - matches d = d ^. L.source == Just (T.pack source) - - handleMessages = handleDiagnostic <|> handleCustomMethodResponse <|> ignoreOthers - handleDiagnostic = do - diagsNot <- Test.message STextDocumentPublishDiagnostics - let fileUri = diagsNot ^. L.params . L.uri - (List diags) = diagsNot ^. L.params . L.diagnostics - res = filter matches diags - if fileUri == document ^. L.uri && not (null res) - then return diags else handleMessages - handleCustomMethodResponse = - -- the CustomClientMethod triggers a RspCustomServer - -- handle that and then exit - void (Test.satisfyMaybe responseForNonExistentMethod) >> return [] - - responseForNonExistentMethod :: FromServerMessage -> Maybe FromServerMessage - responseForNonExistentMethod notif - | FromServerMess SWindowLogMessage logMsg <- notif, - "non-existent-method" `T.isInfixOf` (logMsg ^. L.params . L.message) = Just notif - | otherwise = Nothing - - ignoreOthers = void Test.anyMessage >> handleMessages - -failIfSessionTimeout :: IO a -> IO a -failIfSessionTimeout action = action `catch` errorHandler - where errorHandler :: Test.SessionException -> IO a - errorHandler e@(Test.Timeout _) = assertFailure $ show e - errorHandler e = throwIO e - --- | To locate a symbol, we provide a path to the file from the HLS root --- directory, the line number, and the column number. (0 indexed.) -type SymbolLocation = (FilePath, Int, Int) - -expectSameLocations :: [Location] -> [SymbolLocation] -> Assertion -actual `expectSameLocations` expected = do - let actual' = - Set.map (\location -> (location ^. L.uri - , location ^. L.range . L.start . L.line - , location ^. L.range . L.start . L.character)) - $ Set.fromList actual - expected' <- Set.fromList <$> - (forM expected $ \(file, l, c) -> do - fp <- canonicalizePath file - return (filePathToUri fp, l, c)) - actual' @?= expected'
@@ -1,35 +1,29 @@-import Data.List.Extra (trimEnd) -import Data.Maybe -import Test.Hls.Util -import Test.Tasty -import Test.Tasty.HUnit -import Test.Tasty.Ingredients.Rerun -import Test.Tasty.Runners ( listingTests, consoleTestReporter) -import System.Process -import System.Environment - -main :: IO () -main = do - flushStackEnvironment - defaultMainWithIngredients - [rerunningTests [listingTests, consoleTestReporter]] $ - testGroup "haskell-language-server-wrapper" [projectGhcVersionTests] - -projectGhcVersionTests :: TestTree -projectGhcVersionTests = testGroup "--project-ghc-version" - [ testCase "stack with ghc 8.10.4" $ - testDir "test/wrapper/testdata/stack-8.10.4" "8.10.4" - , testCase "stack with ghc 8.8.3" $ - testDir "test/wrapper/testdata/stack-8.8.3" "8.8.3" - , testCase "cabal with global ghc" $ do - ghcVer <- trimEnd <$> readProcess "ghc" ["--numeric-version"] "" - testDir "test/wrapper/testdata/cabal-cur-ver" ghcVer - ] - -testDir :: FilePath -> String -> Assertion -testDir dir expectedVer = - withCurrentDirectoryInTmp dir $ do - testExe <- fromMaybe "haskell-language-server-wrapper" - <$> lookupEnv "HLS_WRAPPER_TEST_EXE" - actualVer <- trimEnd <$> readProcess testExe ["--project-ghc-version"] "" - actualVer @?= expectedVer +import Data.List.Extra (trimEnd)+import Data.Maybe+import System.Environment+import System.Process+import Test.Hls++main :: IO ()+main = do+ flushStackEnvironment+ defaultTestRunner $ testGroup "haskell-language-server-wrapper" [projectGhcVersionTests]++projectGhcVersionTests :: TestTree+projectGhcVersionTests = testGroup "--project-ghc-version"+ [ testCase "stack with ghc 8.10.4" $+ testDir "test/wrapper/testdata/stack-8.10.4" "8.10.4"+ , testCase "stack with ghc 8.8.3" $+ testDir "test/wrapper/testdata/stack-8.8.3" "8.8.3"+ , testCase "cabal with global ghc" $ do+ ghcVer <- trimEnd <$> readProcess "ghc" ["--numeric-version"] ""+ testDir "test/wrapper/testdata/cabal-cur-ver" ghcVer+ ]++testDir :: FilePath -> String -> Assertion+testDir dir expectedVer =+ withCurrentDirectoryInTmp dir $ do+ testExe <- fromMaybe "haskell-language-server-wrapper"+ <$> lookupEnv "HLS_WRAPPER_TEST_EXE"+ actualVer <- trimEnd <$> readProcess testExe ["--project-ghc-version"] ""+ actualVer @?= expectedVer