├── .azure ├── linux-cabal.bashrc ├── linux-cabal.yml ├── linux-installhs-stack.yml ├── linux-stack.bashrc ├── linux-stack.yml ├── macos-cabal.bashrc ├── macos-installhs-cabal.yml ├── macos-installhs-stack.yml ├── macos-stack.bashrc ├── macos-stack.yml ├── windows-cabal.bashrc ├── windows-cabal.yml ├── windows-installhs-cabal.yml ├── windows-installhs-stack.yml ├── windows-stack.bashrc └── windows-stack.yml ├── .circleci └── config.yml ├── .gitignore ├── .gitmodules ├── .travis.yml.off ├── Changelog.md ├── GenChangelogs.hs ├── LICENSE ├── README.md ├── Setup.hs ├── app ├── HieWrapper.hs ├── MainHie.hs └── RunTest.hs ├── appveyor.yml ├── azure-pipelines.yml ├── cabal-hie-install ├── cabal-hie-install.cmd ├── cabal.project ├── cabal.project-8.6.5 ├── docs ├── Architecture.md ├── Build.md ├── Challenges.md ├── CircleCI.md ├── Design.md ├── Dispatch.md ├── Hacking.md ├── HaskellX2018.pdf ├── IDE-Support-in-GHC-HIW-2017.pdf ├── IdeIntegration.md ├── Inspirations.md ├── Makefile ├── Packages.md ├── Protocol.md ├── Report-2015-11.md ├── Report-2015-12.md ├── Report-2016-01.md ├── Report-2017-07.md ├── Tools.md ├── Wishlists.md ├── emacs.md ├── hcar │ ├── 2015.tex │ ├── 2016.tex │ ├── Makefile │ └── hcar.sty ├── leksah.md ├── make.bat └── source │ ├── conf.py │ ├── hiedomain.py │ └── index.rst ├── haskell-ide-engine.cabal ├── hie-plugin-api ├── Haskell │ └── Ide │ │ └── Engine │ │ ├── ArtifactMap.hs │ │ ├── Compat.hs │ │ ├── Config.hs │ │ ├── Context.hs │ │ ├── Cradle.hs │ │ ├── Ghc.hs │ │ ├── GhcCompat.hs │ │ ├── GhcModuleCache.hs │ │ ├── GhcUtils.hs │ │ ├── Logger.hs │ │ ├── ModuleCache.hs │ │ ├── MonadFunctions.hs │ │ ├── MonadTypes.hs │ │ ├── MultiThreadState.hs │ │ ├── PluginApi.hs │ │ ├── PluginUtils.hs │ │ ├── PluginsIdeMonads.hs │ │ └── TypeMap.hs ├── LICENSE └── hie-plugin-api.cabal ├── hie.yaml.cbl ├── hie.yaml.stack ├── install.hs ├── install ├── Setup.hs ├── cabal.project ├── hie-install.cabal ├── shake.project ├── shake.yaml └── src │ ├── BuildSystem.hs │ ├── Cabal.hs │ ├── Env.hs │ ├── Help.hs │ ├── HieInstall.hs │ ├── Print.hs │ ├── Stack.hs │ └── Version.hs ├── licenses └── xmonad-contrib ├── logos ├── HIE_logo.svg ├── HIE_logo_1024.png ├── HIE_logo_128.png ├── HIE_logo_256.png ├── HIE_logo_32.png ├── HIE_logo_512.png └── HIE_logo_64.png ├── shell.nix ├── src └── Haskell │ └── Ide │ └── Engine │ ├── Channel.hs │ ├── CodeActions.hs │ ├── Completions.hs │ ├── Options.hs │ ├── Plugin │ ├── ApplyRefact.hs │ ├── Brittany.hs │ ├── Example2.hs │ ├── Floskell.hs │ ├── Generic.hs │ ├── GhcMod.hs │ ├── Haddock.hs │ ├── HfaAlign.hs │ ├── HsImport.hs │ ├── Liquid.hs │ ├── Ormolu.hs │ ├── Package.hs │ ├── Package │ │ └── Compat.hs │ └── Pragmas.hs │ ├── Reactor.hs │ ├── Scheduler.hs │ ├── Server.hs │ ├── Support │ ├── FromHaRe.hs │ ├── Fuzzy.hs │ ├── HieExtras.hs │ └── Hoogle.hs │ ├── Types.hs │ └── Version.hs ├── stack-8.4.2.yaml ├── stack-8.4.3.yaml ├── stack-8.4.4.yaml ├── stack-8.6.4.yaml ├── stack-8.6.5.yaml ├── stack-8.8.2.yaml ├── stack-8.8.3.yaml ├── stack.yaml ├── test ├── dispatcher │ └── Main.hs ├── functional │ ├── CommandSpec.hs │ ├── CompletionSpec.hs │ ├── DeferredSpec.hs │ ├── DefinitionSpec.hs │ ├── DiagnosticsSpec.hs │ ├── FormatSpec.hs │ ├── FunctionalBadProjectSpec.hs │ ├── FunctionalCodeActionsSpec.hs │ ├── FunctionalLiquidSpec.hs │ ├── FunctionalSpec.hs │ ├── HieBiosSpec.hs │ ├── HighlightSpec.hs │ ├── HoverSpec.hs │ ├── Main.hs │ ├── ProgressSpec.hs │ ├── ReferencesSpec.hs │ ├── RenameSpec.hs │ ├── SymbolsSpec.hs │ ├── TypeDefinitionSpec.hs │ └── Utils.hs ├── plugin-dispatcher │ └── Main.hs ├── testdata │ ├── .hlint.yaml │ ├── ApplyRefact.hs │ ├── ApplyRefact2.hs │ ├── ApplyRefactError.hs │ ├── BrittanyCRLF.hs │ ├── BrittanyLF.hs │ ├── CodeActionImport.hs │ ├── CodeActionImportBrittany.hs │ ├── CodeActionImportList.hs │ ├── CodeActionImportListElaborate.hs │ ├── CodeActionOnly.hs │ ├── CodeActionRename.hs │ ├── FileWithWarning.hs │ ├── Format.hs │ ├── FuncTest.hs │ ├── FuncTestError.hs │ ├── FuncTestFail.hs │ ├── GhcModCaseSplit.hs │ ├── HaReCase.hs │ ├── HaReDemote.hs │ ├── HaReGA1 │ │ ├── HaReGA1.cabal │ │ ├── HaReGA1.hs │ │ └── cabal.project │ ├── HaReLift.hs │ ├── HaReMoveDef.hs │ ├── HaReRename.hs │ ├── Highlight.hs │ ├── HlintNoRefactorings.hs │ ├── HlintParseFail.hs │ ├── HlintPragma.hs │ ├── Hover.hs │ ├── References.hs │ ├── Rename.hs │ ├── Symbols.hs │ ├── TopLevelSignature.hs │ ├── TypedHoles.hs │ ├── TypedHoles2.hs │ ├── Types.hs │ ├── UnusedTerm.hs │ ├── addPackageTest │ │ ├── cabal-exe │ │ │ ├── AddPackage.hs │ │ │ └── add-package-test.cabal │ │ ├── cabal-lib │ │ │ ├── AddPackage.hs │ │ │ └── add-package-test.cabal │ │ ├── hpack-exe │ │ │ ├── app │ │ │ │ └── Asdf.hs │ │ │ ├── asdf.cabal │ │ │ └── package.yaml │ │ ├── hpack-lib │ │ │ ├── app │ │ │ │ └── Asdf.hs │ │ │ └── package.yaml │ │ └── invalid │ │ │ └── AddPackage.hs │ ├── addPragmas │ │ ├── NeedsPragmas.hs │ │ └── test.cabal │ ├── badProjects │ │ └── cabal │ │ │ ├── Foo.hs │ │ │ └── bad-cabal.cabal │ ├── cabal-helper │ │ ├── implicit-exe │ │ │ ├── Setup.hs │ │ │ ├── cabal.project │ │ │ ├── implicit-exe.cabal │ │ │ └── src │ │ │ │ ├── Exe.hs │ │ │ │ └── Lib.hs │ │ ├── mono-repo │ │ │ ├── A │ │ │ │ ├── A.cabal │ │ │ │ ├── Main.hs │ │ │ │ ├── MyLib.hs │ │ │ │ └── Setup.hs │ │ │ ├── B │ │ │ │ ├── B.cabal │ │ │ │ ├── Main.hs │ │ │ │ ├── MyLib.hs │ │ │ │ └── Setup.hs │ │ │ ├── C │ │ │ │ ├── C.cabal │ │ │ │ ├── MyLib.hs │ │ │ │ └── Setup.hs │ │ │ └── cabal.project │ │ ├── multi-source-dirs │ │ │ ├── Setup.hs │ │ │ ├── multi-source-dirs.cabal │ │ │ └── src │ │ │ │ ├── BetterLib.hs │ │ │ │ └── input │ │ │ │ └── Lib.hs │ │ ├── simple-cabal │ │ │ ├── MyLib.hs │ │ │ ├── Setup.hs │ │ │ └── simple-cabal-test.cabal │ │ ├── simple-stack │ │ │ ├── MyLib.hs │ │ │ ├── Setup.hs │ │ │ └── simple-stack-test.cabal │ │ └── sub-package │ │ │ ├── Setup.hs │ │ │ ├── app │ │ │ └── Main.hs │ │ │ ├── plugins-api │ │ │ ├── PluginLib.hs │ │ │ ├── Setup.hs │ │ │ └── plugins-api.cabal │ │ │ ├── src │ │ │ └── MyLib.hs │ │ │ └── sub-package.cabal │ ├── completion │ │ ├── Completion.hs │ │ ├── Context.hs │ │ ├── DupRecFields.hs │ │ └── completions.cabal │ ├── context │ │ ├── ExampleContext.hs │ │ └── Foo │ │ │ └── Bar.hs │ ├── definition │ │ ├── Bar.hs │ │ ├── Foo.hs │ │ └── definitions.cabal │ ├── gototest │ │ ├── Setup.hs │ │ ├── app │ │ │ └── Main.hs │ │ ├── cabal.project │ │ ├── gototest.cabal │ │ └── src │ │ │ ├── Lib.hs │ │ │ └── Lib2.hs │ ├── hieBiosError │ │ └── Foo.hs │ ├── hieBiosMainIs │ │ ├── Main.hs │ │ ├── Setup.hs │ │ └── hieBiosMainIs.cabal │ ├── liquid │ │ └── Evens.hs │ ├── redundantImportTest │ │ ├── src │ │ │ ├── CodeActionRedundant.hs │ │ │ └── MultipleImports.hs │ │ └── test.cabal │ ├── testdata.cabal │ ├── typedHoleDiag.txt │ ├── typedHoleDiag2.txt │ ├── typedHoleDiag3.txt │ ├── wErrorTest │ │ ├── src │ │ │ └── WError.hs │ │ └── test.cabal │ └── wrapper │ │ ├── 8.8.1 │ │ ├── Setup.hs │ │ ├── cabal1.cabal │ │ ├── hie.yaml │ │ ├── src │ │ │ ├── Foo │ │ │ │ └── Bar.hs │ │ │ └── main.hs │ │ └── stack.yaml │ │ ├── ghc │ │ └── dummy │ │ └── lts-14.18 │ │ ├── Setup.hs │ │ ├── cabal1.cabal │ │ ├── hie.yaml │ │ ├── src │ │ ├── Foo │ │ │ └── Bar.hs │ │ └── main.hs │ │ └── stack.yaml ├── unit │ ├── ApplyRefactPluginSpec.hs │ ├── CabalHelperSpec.hs │ ├── CodeActionsSpec.hs │ ├── ContextSpec.hs │ ├── DiffSpec.hs │ ├── ExtensibleStateSpec.hs │ ├── GenericPluginSpec.hs │ ├── GhcModPluginSpec.hs │ ├── HooglePluginSpec.hs │ ├── HsImportSpec.hs │ ├── JsonSpec.hs │ ├── LiquidSpec.hs │ ├── Main.hs │ ├── OptionsSpec.hs │ ├── PackagePluginSpec.hs │ └── Spec.hs ├── utils │ └── TestUtils.hs └── wrapper │ └── HieWrapper.hs └── update-index-state.sh /.azure/linux-cabal.bashrc: -------------------------------------------------------------------------------- 1 | if [ -z "$PROJECT_FILE" ]; then 2 | export PROJECT_FILE="cabal.project" 3 | if [ -f "cabal.project-$GHC_VERSION" ]; then 4 | export PROJECT_FILE="cabal.project-$GHC_VERSION" 5 | fi 6 | fi 7 | export PATH=$HOME/.cabal/bin:/opt/cabal/$CABAL_VERSION/bin:/opt/ghc/$GHC_VERSION/bin:$HOME/.local/bin:$PATH 8 | -------------------------------------------------------------------------------- /.azure/linux-cabal.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: Linux_Cabal 3 | timeoutInMinutes: 0 4 | pool: 5 | vmImage: ubuntu-16.04 6 | strategy: 7 | matrix: 8 | ghc-8.8.3: 9 | GHC_VERSION: "8.8.3" 10 | ghc-8.8.2: 11 | GHC_VERSION: "8.8.2" 12 | ghc-8.6.5: 13 | GHC_VERSION: "8.6.5" 14 | ghc-8.4.4: 15 | GHC_VERSION: "8.4.4" 16 | variables: 17 | CABAL_VERSION: "3.0" 18 | LIQUID_VERSION: "0.8.6.2" 19 | steps: 20 | - task: Cache@2 21 | inputs: 22 | key: '"cabal" | "$(Agent.OS)" | "$(CABAL_VERSION)" | "$(GHC_VERSION)" | $(Build.SourcesDirectory)/cabal.project | $(Build.SourcesDirectory)/haskell-ide-engine.cabal | $(Build.SourcesDirectory)/hie-plugin-api/hie-plugin-api.cabal' 23 | path: .azure-cache 24 | cacheHitVar: CACHE_RESTORED 25 | displayName: "Download cache" 26 | - bash: | 27 | mkdir -p $HOME/.cabal 28 | tar -vxzf .azure-cache/cabal-root.tar.gz -C / 29 | mkdir -p $HOME/.ghc 30 | tar -vxzf .azure-cache/ghc-root.tar.gz -C / 31 | mkdir -p dist-newstyle 32 | tar -vxzf .azure-cache/cabal-dist.tar.gz 33 | displayName: "Unpack cache" 34 | condition: eq(variables.CACHE_RESTORED, 'true') 35 | - bash: | 36 | git submodule sync 37 | git submodule update --init 38 | displayName: Sync submodules 39 | - bash: | 40 | # To install ghc if they are not yet included in the agent image 41 | ghc --version || (sudo apt-get update && sudo apt-get install -y ghc-$GHC_VERSION) 42 | displayName: Install ghc 43 | - bash: | 44 | source .azure/linux-cabal.bashrc 45 | cabal v2-update --project-file $PROJECT_FILE 46 | echo "overwrite-policy: always" >> $HOME/.cabal/config 47 | displayName: Update cabal 48 | - bash: | 49 | source .azure/linux-cabal.bashrc 50 | cabal v2-build --disable-tests --disable-benchmarks --only-dependencies --project-file $PROJECT_FILE 51 | displayName: Build dependencies 52 | - bash: | 53 | source .azure/linux-cabal.bashrc 54 | cabal v2-build --disable-tests --disable-benchmarks --project-file $PROJECT_FILE 55 | displayName: Build `hie` 56 | - bash: | 57 | source .azure/linux-cabal.bashrc 58 | cabal v2-install --project-file $PROJECT_FILE # `hie` binary required locally for tests 59 | displayName: Install `hie` 60 | - bash: | 61 | source .azure/linux-cabal.bashrc 62 | cabal v2-build --enable-tests --enable-benchmarks --only-dependencies --project-file $PROJECT_FILE 63 | displayName: Build Test-dependencies 64 | - bash: | 65 | sudo apt update 66 | sudo apt install z3 67 | displayName: "Install Runtime Test-Dependencies: z3" 68 | - bash: | 69 | source .azure/linux-cabal.bashrc 70 | cd $(Agent.TempDirectory) 71 | cabal v2-install liquidhaskell-$LIQUID_VERSION -w /opt/ghc/8.6.5/bin/ghc 72 | displayName: "Install Runtime Test-Dependencies: liquidhaskell" 73 | - bash: | 74 | source .azure/linux-cabal.bashrc 75 | cabal v2-build hoogle --project-file $PROJECT_FILE 76 | cabal v2-exec hoogle generate --project-file $PROJECT_FILE 77 | displayName: "Install Runtime Test-Dependencies: hoogle database" 78 | - bash: | 79 | source .azure/linux-cabal.bashrc 80 | cabal v2-test :unit-test --project-file $PROJECT_FILE 81 | displayName: "Run Test: unit-test" 82 | - bash: | 83 | source .azure/linux-cabal.bashrc 84 | cabal v2-test :dispatcher-test :plugin-dispatcher-test :wrapper-test --project-file $PROJECT_FILE 85 | displayName: "Run Test: dispatcher-test, plugin-dispatcher-test and wrapper-test" 86 | - bash: | 87 | source .azure/linux-cabal.bashrc 88 | cabal v2-test :func-test --project-file $PROJECT_FILE 89 | displayName: "Run Test: func-test" 90 | - bash: | 91 | mkdir -p .azure-cache 92 | tar -vczf .azure-cache/cabal-root.tar.gz $HOME/.cabal 93 | tar -vczf .azure-cache/ghc-root.tar.gz $HOME/.ghc 94 | tar -vczf .azure-cache/cabal-dist.tar.gz dist-newstyle 95 | displayName: "Pack cache" -------------------------------------------------------------------------------- /.azure/linux-installhs-stack.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: Linux_installhs_Stack 3 | timeoutInMinutes: 0 4 | pool: 5 | vmImage: ubuntu-16.04 6 | variables: 7 | YAML_FILE: install/shake.yaml 8 | steps: 9 | - task: Cache@2 10 | inputs: 11 | key: '"stack" | "$(Agent.OS)" | $(Build.SourcesDirectory)/$(YAML_FILE) | $(Build.SourcesDirectory)/install/shake.yaml' 12 | path: .azure-cache 13 | cacheHitVar: CACHE_RESTORED 14 | displayName: "Cache stack-root" 15 | - bash: | 16 | mkdir -p $STACK_ROOT 17 | tar -vxzf .azure-cache/stack-root.tar.gz -C / 18 | mkdir -p .stack-work 19 | tar -vxzf .azure-cache/stack-work.tar.gz 20 | mkdir -p ./install/.stack-work 21 | tar -vxzf .azure-cache/install-stack-work.tar.gz 22 | displayName: "Unpack cache" 23 | condition: eq(variables.CACHE_RESTORED, 'true') 24 | - bash: | 25 | export STACK_ROOT="$(Build.SourcesDirectory)"/.stack-root 26 | mkdir -p ~/.local/bin 27 | curl -L https://get.haskellstack.org/stable/linux-x86_64.tar.gz | \ 28 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack' 29 | displayName: Install stack 30 | - bash: | 31 | source .azure/linux-stack.bashrc 32 | stack setup --stack-yaml $(YAML_FILE) 33 | displayName: Install GHC 34 | - bash: | 35 | source .azure/linux-stack.bashrc 36 | stack --stack-yaml $(YAML_FILE) --install-ghc build --only-dependencies 37 | displayName: Build dependencies 38 | - bash: | 39 | source .azure/linux-stack.bashrc 40 | stack build --stack-yaml $(YAML_FILE) 41 | displayName: Build `hie-install` 42 | - bash: | 43 | source .azure/linux-stack.bashrc 44 | stack install.hs help 45 | displayName: Run help of `install.hs` 46 | - bash: | 47 | source .azure/linux-stack.bashrc 48 | stack install.hs latest 49 | displayName: Run latest target of `install.hs` 50 | - bash: | 51 | mkdir -p .azure-cache 52 | tar -vczf .azure-cache/stack-root.tar.gz $(cygpath $STACK_ROOT) 53 | tar -vczf .azure-cache/stack-work.tar.gz .stack-work 54 | tar -vczf .azure-cache/install-stack-work.tar.gz ./install/.stack-work 55 | displayName: "Pack cache" 56 | -------------------------------------------------------------------------------- /.azure/linux-stack.bashrc: -------------------------------------------------------------------------------- 1 | export PATH=$HOME/.local/bin:/opt/ghc/$GHC_VERSION/bin:$PATH 2 | -------------------------------------------------------------------------------- /.azure/macos-cabal.bashrc: -------------------------------------------------------------------------------- 1 | if [ -z "$PROJECT_FILE" ]; then 2 | export PROJECT_FILE="cabal.project" 3 | if [ -f "cabal.project-$GHC_VERSION" ]; then 4 | export PROJECT_FILE="cabal.project-$GHC_VERSION" 5 | fi 6 | fi 7 | export CABAL_ROOT=$HOME/.cabal 8 | export PATH=$CABAL_ROOT/bin:$PATH 9 | -------------------------------------------------------------------------------- /.azure/macos-installhs-cabal.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: MacOs_installhs_Cabal 3 | timeoutInMinutes: 0 4 | pool: 5 | vmImage: macOS-10.14 6 | variables: 7 | PROJECT_FILE: "./install/shake.project" 8 | steps: 9 | - task: Cache@2 10 | inputs: 11 | key: '"cabal-installhs" | "$(Agent.OS)" | $(Build.SourcesDirectory)/cabal.project | $(Build.SourcesDirectory)/haskell-ide-engine.cabal | $(Build.SourcesDirectory)/hie-plugin-api/hie-plugin-api.cabal' 12 | path: .azure-cache 13 | cacheHitVar: CACHE_RESTORED 14 | displayName: "Download cache" 15 | - bash: | 16 | source .azure/macos-cabal.bashrc 17 | mkdir -p $CABAL_ROOT 18 | tar -vxzf .azure-cache/cabal-root.tar.gz -C / 19 | mkdir -p dist-newstyle 20 | tar -vxzf .azure-cache/cabal-dist.tar.gz 21 | displayName: "Unpack cache" 22 | condition: eq(variables.CACHE_RESTORED, 'true') 23 | - bash: | 24 | brew install ghc@8.8 25 | brew install cabal-install --ignore-dependencies ghc 26 | which cabal 27 | which ghc 28 | cabal update 29 | displayName: Install cabal and ghc 30 | - bash: | 31 | export PATH="/usr/local/opt/ghc@8.6/bin:$PATH" 32 | source .azure/windows-cabal.bashrc 33 | cabal v2-run ./install.hs --project-file $PROJECT_FILE -- help 34 | displayName: Run help of `install.hs` 35 | - bash: | 36 | export PATH="/usr/local/opt/ghc@8.6/bin:$PATH" 37 | source .azure/windows-cabal.bashrc 38 | cabal v2-run ./install.hs --project-file $PROJECT_FILE -- latest 39 | displayName: Run latest target of `install.hs` 40 | - bash: | 41 | source .azure/macos-cabal.bashrc 42 | mkdir -p .azure-cache 43 | tar -vczf .azure-cache/cabal-root.tar.gz $CABAL_ROOT 44 | tar -vczf .azure-cache/cabal-dist.tar.gz dist-newstyle 45 | displayName: "Pack cache" 46 | -------------------------------------------------------------------------------- /.azure/macos-installhs-stack.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: MacOs_installhs_Stack 3 | timeoutInMinutes: 0 4 | pool: 5 | vmImage: macOS-10.14 6 | variables: 7 | YAML_FILE: install/shake.yaml 8 | steps: 9 | - task: Cache@2 10 | inputs: 11 | key: '"stack" | "$(Agent.OS)" | $(Build.SourcesDirectory)/$(YAML_FILE) | $(Build.SourcesDirectory)/install/shake.yaml' 12 | path: .azure-cache 13 | cacheHitVar: CACHE_RESTORED 14 | displayName: "Cache stack-root" 15 | - bash: | 16 | mkdir -p $STACK_ROOT 17 | tar -vxzf .azure-cache/stack-root.tar.gz -C / 18 | mkdir -p .stack-work 19 | tar -vxzf .azure-cache/stack-work.tar.gz 20 | mkdir -p ./install/.stack-work 21 | tar -vxzf .azure-cache/install-stack-work.tar.gz 22 | displayName: "Unpack cache" 23 | condition: eq(variables.CACHE_RESTORED, 'true') 24 | - bash: | 25 | export STACK_ROOT="$(Build.SourcesDirectory)"/.stack-root 26 | mkdir -p ~/.local/bin 27 | curl -skL https://get.haskellstack.org/stable/osx-x86_64.tar.gz | \ 28 | tar xz --strip-components=1 --include '*/stack' -C ~/.local/bin; 29 | displayName: Install stack 30 | - bash: | 31 | source .azure/macos-stack.bashrc 32 | stack setup --stack-yaml $(YAML_FILE) 33 | displayName: Install GHC 34 | - bash: | 35 | source .azure/macos-stack.bashrc 36 | stack --stack-yaml $(YAML_FILE) --install-ghc build --only-dependencies 37 | displayName: Build dependencies 38 | - bash: | 39 | source .azure/macos-stack.bashrc 40 | stack build --stack-yaml $(YAML_FILE) 41 | displayName: Build `hie-install` 42 | - bash: | 43 | source .azure/macos-stack.bashrc 44 | stack install.hs help 45 | displayName: Run help of `install.hs` 46 | - bash: | 47 | source .azure/macos-stack.bashrc 48 | stack install.hs latest 49 | displayName: Run latest target of `install.hs` 50 | - bash: | 51 | mkdir -p .azure-cache 52 | tar -vczf .azure-cache/stack-root.tar.gz $(cygpath $STACK_ROOT) 53 | tar -vczf .azure-cache/stack-work.tar.gz .stack-work 54 | tar -vczf .azure-cache/install-stack-work.tar.gz ./install/.stack-work 55 | displayName: "Pack cache" 56 | -------------------------------------------------------------------------------- /.azure/macos-stack.bashrc: -------------------------------------------------------------------------------- 1 | export PATH=$HOME/.local/bin:$PATH 2 | -------------------------------------------------------------------------------- /.azure/windows-cabal.bashrc: -------------------------------------------------------------------------------- 1 | if [ -z "$PROJECT_FILE" ]; then 2 | export PROJECT_FILE="cabal.project" 3 | if [ -f "cabal.project-$GHC_VERSION" ]; then 4 | export PROJECT_FILE="cabal.project-$GHC_VERSION" 5 | fi 6 | fi 7 | if [ -z "$CABAL_DIR" ]; then 8 | CABAL_DIR="$APPDATA\\cabal" 9 | fi 10 | export GHCS_PATH=$(cygpath $ProgramData)/chocolatey/lib/ghc/tools 11 | export GHC_PATH=$GHCS_PATH/ghc-$GHC_VERSION 12 | export CABAL_ROOT=$(cygpath $CABAL_DIR) 13 | export Z3_BIN_PATH=/usr/local/z3-4.8.5-x64-win/bin 14 | export PATH=$CABAL_ROOT/bin:$GHC_PATH/bin:$Z3_BIN_PATH:$PATH 15 | -------------------------------------------------------------------------------- /.azure/windows-installhs-cabal.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: Windows_installhs_Cabal 3 | timeoutInMinutes: 0 4 | pool: 5 | vmImage: windows-2019 6 | variables: 7 | GHC_VERSION: "8.6.5" 8 | CABAL_VERSION: "3.0.0.0" 9 | CABAL_DIR: "" # To use the default one (cabal-hie-install latest fails with a custom one) 10 | CABAL_STORE_DIR: "C:\\sd" 11 | PROJECT_FILE: "./install/shake.project" 12 | steps: 13 | - task: Cache@2 14 | inputs: 15 | key: '"cabal-installhs-v1" | "$(Agent.OS)" | "$(CABAL_VERSION)" | "$(GHC_VERSION)" | $(Build.SourcesDirectory)/cabal.project | $(Build.SourcesDirectory)/haskell-ide-engine.cabal | $(Build.SourcesDirectory)/hie-plugin-api/hie-plugin-api.cabal' 16 | path: .azure-cache 17 | cacheHitVar: CACHE_RESTORED 18 | displayName: "Download cache" 19 | - bash: | 20 | source .azure/windows-cabal.bashrc 21 | mkdir -p $CABAL_ROOT 22 | tar -vxzf .azure-cache/cabal-root.tar.gz -C /c 23 | mkdir -p $CABAL_STORE_DIR 24 | tar -vxzf .azure-cache/cabal-store.tar.gz -C /c 25 | mkdir -p ./dist-newstyle 26 | tar -vxzf .azure-cache/cabal-dist.tar.gz 27 | displayName: "Unpack cache" 28 | condition: eq(variables.CACHE_RESTORED, 'true') 29 | - bash: | 30 | choco install -y --ignore-dependencies ghc --version=$GHC_VERSION 31 | displayName: Install ghc 32 | - bash: | 33 | source .azure/windows-cabal.bashrc 34 | choco install -y cabal --version=$CABAL_VERSION 35 | $(cygpath $ProgramData)/chocolatey/bin/RefreshEnv.cmd 36 | displayName: Install cabal 37 | - bash: | 38 | source .azure/windows-cabal.bashrc 39 | cabal v2-update 40 | echo "store-dir: $CABAL_STORE_DIR" >> $CABAL_ROOT/config 41 | displayName: Update cabal 42 | - bash: | 43 | source .azure/windows-cabal.bashrc 44 | cabal v2-run ./install.hs --project-file $PROJECT_FILE help 45 | displayName: Run help of `install.hs` 46 | - bash: | 47 | source .azure/windows-cabal.bashrc 48 | cabal v2-run ./install.hs --project-file $PROJECT_FILE latest 49 | displayName: Run latest target of `install.hs` 50 | - bash: | 51 | source .azure/windows-cabal.bashrc 52 | mkdir -p .azure-cache 53 | tar -vczf .azure-cache/cabal-root.tar.gz $CABAL_ROOT 54 | tar -vczf .azure-cache/cabal-store.tar.gz $(cygpath $CABAL_STORE_DIR) 55 | tar -vczf .azure-cache/cabal-dist.tar.gz dist-newstyle 56 | displayName: "Pack cache" 57 | 58 | -------------------------------------------------------------------------------- /.azure/windows-installhs-stack.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: Windows_installhs_Stack 3 | timeoutInMinutes: 0 4 | pool: 5 | vmImage: windows-2019 6 | variables: 7 | YAML_FILE: install/shake.yaml 8 | STACK_ROOT: "C:\\sr" 9 | GHC_VERSION: "8.6.5" 10 | steps: 11 | - task: Cache@2 12 | inputs: 13 | key: '"stack-installhs-v1" | "$(Agent.OS)" | $(Build.SourcesDirectory)/$(YAML_FILE) | $(Build.SourcesDirectory)/install/shake.yaml' 14 | path: .azure-cache 15 | cacheHitVar: CACHE_RESTORED 16 | displayName: "Cache stack-root" 17 | - bash: | 18 | mkdir -p "$STACK_ROOT" 19 | tar -vxzf .azure-cache/stack-root.tar.gz -C /c 20 | mkdir -p .stack-work 21 | tar -vxzf .azure-cache/stack-work.tar.gz 22 | mkdir -p ./install/.stack-work 23 | tar -vxzf .azure-cache/install-stack-work.tar.gz 24 | displayName: "Unpack cache" 25 | condition: eq(variables.CACHE_RESTORED, 'true') 26 | - bash: | 27 | curl -sSkL http://www.stackage.org/stack/windows-x86_64 -o /usr/bin/stack.zip 28 | unzip -o /usr/bin/stack.zip -d /usr/bin/ 29 | mkdir -p "$STACK_ROOT" 30 | displayName: Install stack 31 | - bash: | 32 | source .azure/windows-stack.bashrc 33 | stack setup --stack-yaml $(YAML_FILE) 34 | displayName: Install GHC 35 | - bash: | 36 | source .azure/windows-stack.bashrc 37 | stack --stack-yaml $(YAML_FILE) build --only-dependencies 38 | displayName: Build dependencies 39 | - bash: | 40 | source .azure/windows-stack.bashrc 41 | stack build --stack-yaml $(YAML_FILE) 42 | displayName: Build `hie-install` 43 | - bash: | 44 | source .azure/windows-stack.bashrc 45 | stack install.hs help 46 | displayName: Run help of `install.hs` 47 | - bash: | 48 | source .azure/windows-stack.bashrc 49 | # Some executions fails with spurious errors installing executables 50 | # We can't install the latest target cause it is ghc-8.8.3 and throws segfaults 51 | stack install.hs hie-${GHC_VERSION} || stack install.hs hie-${GHC_VERSION} 52 | displayName: Run latest target of `install.hs` 53 | - bash: | 54 | mkdir -p .azure-cache 55 | tar -vczf .azure-cache/stack-root.tar.gz $(cygpath $STACK_ROOT) 56 | tar -vczf .azure-cache/stack-work.tar.gz .stack-work 57 | tar -vczf .azure-cache/install-stack-work.tar.gz ./install/.stack-work 58 | displayName: "Pack cache" 59 | -------------------------------------------------------------------------------- /.azure/windows-stack.bashrc: -------------------------------------------------------------------------------- 1 | if [ -z "$CABAL_DIR" ]; then 2 | CABAL_DIR="$APPDATA\\cabal" 3 | fi 4 | export LOCAL_BIN_PATH=$(cygpath $APPDATA\\local\\bin) 5 | export CABAL_ROOT=$(cygpath $CABAL_DIR) 6 | export Z3_BIN_PATH=/usr/local/z3-4.8.5-x64-win/bin 7 | export PATH=$Z3_BIN_PATH:$LOCAL_BIN_PATH:$PATH 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.aux 2 | *.chi 3 | *.chs.h 4 | *.dyn_hi 5 | *.dyn_o 6 | *.hi 7 | *.hp 8 | *.imports 9 | *.kdev4 10 | *.liquid 11 | *.log 12 | *.o 13 | *.out 14 | *.prof 15 | *.swp 16 | *.tag 17 | *_flymake.hs 18 | *~ 19 | .#* 20 | .cabal-sandbox/ 21 | .hpc 22 | .hsenv 23 | .stack-work/ 24 | .vagrant/ 25 | /*.iml 26 | /.cabal-project-deps 27 | /.cabal-sandbox/ 28 | /.ghc.environment* 29 | /.idea/ 30 | /.stack-work 31 | /_release/ 32 | /cabal.project.local 33 | /docs/build/ 34 | /docs/hcar/auto/2015.el 35 | /docs/hcar/prv_2015.fmt 36 | /docs/source/__pycache__/ 37 | /docs/source/plugins/ 38 | /elisp/.cask/ 39 | /test/testdata/*.exe 40 | /test/testdata/FuncTest.refactored.hs 41 | /test/testdata/HaReAddRmParam.refactored.hs 42 | /test/testdata/HaReCase.refactored.hs 43 | /test/testdata/HaReDemote.refactored.hs 44 | /test/testdata/HaReGA1.refactored.hs 45 | /test/testdata/HaReMoveDef.refactored.hs 46 | /test/testdata/HaReRename.hs.keep 47 | /test/testdata/HaReRename.refactored.hs 48 | /test/testdata/addPackageTest/**/stack.yaml 49 | /test/testdata/addPackageTest/**/stack.yaml 50 | /test/testdata/addPackageTest/hpack/*.cabal 51 | /test/testdata/badProjects/cabal/stack.yaml 52 | /test/testdata/completion/stack.yaml 53 | /test/testdata/definition/stack.yaml 54 | /test/testdata/gototest/stack.yaml 55 | /test/testdata/redundantImportTest/stack.yaml 56 | /test/testdata/stack.yaml 57 | /test/testdata/wErrorTest/stack.yaml 58 | TAGS 59 | cabal-dev/ 60 | cabal.sandbox.config 61 | dist-newstyle/ 62 | dist 63 | tags 64 | test-logs/ 65 | test-results/ 66 | .DS_Store 67 | 68 | .hspec-failures 69 | /test/testdata/addPragmas/stack.yaml 70 | .vscode 71 | 72 | # shake build information 73 | _build/ 74 | 75 | # stack 2.1 stack.yaml lock files 76 | stack*.yaml.lock 77 | shake.yaml.lock 78 | 79 | # ignore hie.yaml's for testdata 80 | test/**/*.yaml 81 | /hie.yaml 82 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | # To remove a submodule you need to: 2 | # 3 | # Delete the relevant section from the .gitmodules file. 4 | # Stage the .gitmodules changes git add .gitmodules 5 | # Delete the relevant section from .git/config. 6 | # Run git rm --cached path_to_submodule (no trailing slash). 7 | # Run rm -rf .git/modules/path_to_submodule 8 | # Commit git commit -m "Removed submodule " 9 | # Delete the now untracked submodule files 10 | # rm -rf path_to_submodule 11 | -------------------------------------------------------------------------------- /GenChangelogs.hs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env cabal 2 | {- cabal: 3 | build-depends: base, process, html-conduit, http-conduit, xml-conduit, text, containers 4 | -} 5 | 6 | {-# LANGUAGE OverloadedStrings #-} 7 | 8 | import Control.Monad 9 | import Data.Char 10 | import Data.List 11 | import qualified Data.Map.Lazy as M 12 | import Network.HTTP.Simple 13 | import System.Process 14 | import qualified Data.Text as T 15 | import qualified Data.Text.IO as T 16 | import Text.HTML.DOM 17 | import Text.XML.Cursor 18 | import Text.XML (Element(..)) 19 | 20 | main = do 21 | callCommand "git fetch --tags" 22 | tags <- filter (isPrefixOf "0.") . lines <$> 23 | readProcess "git" ["tag", "--list", "--sort=v:refname"] "" 24 | messages <- lines <$> readProcess "git" [ "log" 25 | , last tags <> "..HEAD" 26 | , "--merges" 27 | , "--reverse" 28 | , "--pretty=format:\"%s\"" 29 | ] "" 30 | 31 | let -- try to get "1334" out of "merge PR #1334" 32 | prNums = map (filter isDigit) $ 33 | map head $ 34 | filter (not . null) $ 35 | map (filter (isPrefixOf "#") . words) messages 36 | prUrls = map ("https://github.com/haskell/haskell-ide-engine/pull/" <>) prNums 37 | 38 | (flip mapM_) prUrls $ \url -> do 39 | body <- getResponseBody <$> httpLBS (parseRequest_ url) 40 | let cursor = fromDocument (parseLBS body) 41 | 42 | titles = (descendant >=> attributeIs "class" "js-issue-title" >=> child >=> content) cursor 43 | title = T.unpack $ T.strip $ head titles 44 | 45 | checkAuthor :: Element -> Bool 46 | checkAuthor e = maybe False (T.isInfixOf "author") (M.lookup "class" (elementAttributes e)) 47 | authors = (descendant >=> checkElement checkAuthor >=> child >=> content) cursor 48 | author = T.unpack $ T.strip $ authors !! 2 -- second author is the pr author 49 | 50 | -- generate markdown 51 | putStrLn $ "- [" <> title <> "](" <> url <> ") (@" <> author <> ")" 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016, TBD 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following 14 | disclaimer in the documentation and/or other materials provided 15 | with the distribution. 16 | 17 | * Neither the name of Alan Zimmerman nor the names of other 18 | contributors may be used to endorse or promote products derived 19 | from this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /app/HieWrapper.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | -- | This module is based on the hie-wrapper.sh script in 3 | -- https://github.com/alanz/vscode-hie-server 4 | module Main where 5 | 6 | import Data.List 7 | import Data.Foldable 8 | import HIE.Bios 9 | import Haskell.Ide.Engine.MonadFunctions 10 | import Haskell.Ide.Engine.Cradle (findLocalCradle) 11 | import Haskell.Ide.Engine.Options 12 | import Haskell.Ide.Engine.Version 13 | import System.Directory 14 | import System.Environment 15 | import System.Process 16 | import System.Info 17 | import System.FilePath 18 | 19 | -- --------------------------------------------------------------------- 20 | 21 | main :: IO () 22 | main = do 23 | _opts <- initApp 24 | "hie-wrapper - Launch the appropriate haskell-ide-engine for a given project" 25 | progName <- getProgName 26 | logm $ "run entered for hie-wrapper(" ++ progName ++ ") " ++ hieVersion 27 | d <- getCurrentDirectory 28 | logm $ "Current directory:" ++ d 29 | logm $ "Operating system:" ++ os 30 | args <- getArgs 31 | logm $ "args:" ++ show args 32 | 33 | -- Get the cabal directory from the cradle 34 | cradle <- findLocalCradle (d "File.hs") 35 | let dir = cradleRootDir cradle 36 | logm $ "Cradle directory:" ++ dir 37 | setCurrentDirectory dir 38 | 39 | ghcVersion <- getProjectGhcVersion cradle 40 | logm $ "Project GHC version:" ++ ghcVersion 41 | 42 | let 43 | hieBin = "hie-" ++ ghcVersion 44 | backupHieBin = 45 | case dropWhileEnd (/='.') ghcVersion of 46 | [] -> "hie" 47 | xs -> "hie-" ++ init xs 48 | candidates' = [hieBin, backupHieBin, "hie"] 49 | candidates = map (++ exeExtension) candidates' 50 | 51 | logm $ "hie exe candidates :" ++ show candidates 52 | 53 | mexes <- traverse findExecutable candidates 54 | 55 | case asum mexes of 56 | Nothing -> logm $ "cannot find any hie exe, looked for:" ++ intercalate ", " candidates 57 | Just e -> do 58 | logm $ "found hie exe at:" ++ e 59 | logm $ "args:" ++ show args 60 | logm "launching ....\n\n\n" 61 | callProcess e args 62 | logm "done" 63 | 64 | -- --------------------------------------------------------------------- 65 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | environment: 3 | matrix: 4 | - GHCVER: 8.6.5 5 | - GHCVER: 8.4.4 6 | - GHCVER: 8.4.3 7 | - GHCVER: 8.4.2 8 | install: 9 | - cmd: >- 10 | git submodule update --init --recursive 11 | 12 | choco install -y haskell-stack 13 | 14 | refreshenv 15 | cache: 16 | - '%LOCALAPPDATA%\Programs\stack\' 17 | - c:\sr 18 | build_script: 19 | - cmd: stack --stack-yaml=stack-%GHCVER%.yaml install 20 | test: off 21 | 22 | # we're running out of artifact space, disable for now :( 23 | # artifacts: 24 | # - path: .stack-work\install\**\bin\hie.exe 25 | # - path: .stack-work\install\**\bin\hie-wrapper.exe 26 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Build master, branches starting with `azure` and tags commits 2 | trigger: 3 | branches: 4 | include: 5 | - master 6 | - azure* 7 | tags: 8 | include: 9 | - '*' 10 | paths: 11 | exclude: 12 | - .circleci 13 | - docs 14 | - licenses 15 | - logos 16 | - LICENSE 17 | - '*.md' 18 | 19 | # Enable PR triggers that target the master branch 20 | pr: 21 | autoCancel: true # cancel previous builds on push 22 | branches: 23 | include: 24 | - master 25 | paths: 26 | exclude: 27 | - .circleci 28 | - docs 29 | - licenses 30 | - logos 31 | - LICENSE 32 | - '*.md' 33 | 34 | jobs: 35 | - template: ./.azure/linux-stack.yml 36 | - template: ./.azure/linux-cabal.yml 37 | - template: ./.azure/windows-stack.yml 38 | - template: ./.azure/windows-cabal.yml 39 | - template: ./.azure/macos-stack.yml 40 | - template: ./.azure/linux-installhs-stack.yml 41 | - template: ./.azure/windows-installhs-stack.yml 42 | - template: ./.azure/windows-installhs-cabal.yml 43 | - template: ./.azure/macos-installhs-cabal.yml 44 | - template: ./.azure/macos-installhs-stack.yml 45 | -------------------------------------------------------------------------------- /cabal-hie-install: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cabal v2-run ./install.hs --project-file install/shake.project $@ -------------------------------------------------------------------------------- /cabal-hie-install.cmd: -------------------------------------------------------------------------------- 1 | @cabal v2-run .\install.hs --project-file=install\shake.project %* -------------------------------------------------------------------------------- /cabal.project: -------------------------------------------------------------------------------- 1 | packages: 2 | ./ 3 | ./hie-plugin-api/ 4 | 5 | -- ./submodules/HaRe 6 | 7 | tests: true 8 | 9 | package haskell-ide-engine 10 | test-show-details: direct 11 | 12 | -- Match the flag settings we use in stac builds 13 | constraints: 14 | haskell-ide-engine +pedantic, 15 | hie-plugin-api +pedantic, 16 | ghc-lib-parser == 8.8.2.20200205 17 | 18 | write-ghc-environment-files: never 19 | 20 | index-state: 2020-05-12T16:28:12Z 21 | -------------------------------------------------------------------------------- /cabal.project-8.6.5: -------------------------------------------------------------------------------- 1 | packages: 2 | ./ 3 | ./hie-plugin-api/ 4 | 5 | -- ./submodules/HaRe 6 | 7 | tests: true 8 | 9 | -- The build is failing due a cabal bug involving haddock 10 | -- see https://github.com/haskell/haskell-ide-engine/issues/1741 11 | package haddock-api 12 | documentation: False 13 | 14 | package haskell-ide-engine 15 | test-show-details: direct 16 | 17 | -- Match the flag settings we use in stac builds 18 | constraints: 19 | haskell-ide-engine +pedantic, 20 | hie-plugin-api +pedantic, 21 | ghc-lib-parser == 8.8.2.20200205 22 | 23 | write-ghc-environment-files: never 24 | 25 | index-state: 2020-05-12T16:28:12Z 26 | -------------------------------------------------------------------------------- /docs/Challenges.md: -------------------------------------------------------------------------------- 1 | # Challenges encountered by existing tooling 2 | 3 | ### ghc-mod 4 | 5 | 1. Linking against Cabal directly meant lots of breakage when interacting with the on-disk configuration state. (Since solved by using wrapper) 6 | 2. Supporting ill-defined interfaces and protocols is hard to impossible. Over the course of its almost 100 releases (!!!) compatibility was broken way too often. 7 | 3. Supporting many GHC versions simultaneously is very hard since they keep breaking the API. 8 | 4. Linking against GHC means similar problems as with linking against Cabal, i.e., when the user upgrades their GHC binary stuff will break. 9 | 10 | * :memo: Don't link against Cabal directly ever 11 | * :memo: (maybe) Target only one GHC version at a time or provide some compatibility layer 12 | * :memo: Let's get the interfaces mostly right on the first go 13 | * :memo: Handle changing compiler versions transparently 14 | 15 | ### ide-backend / stack-ide 16 | 17 | 1. For various reasons mainly related to its original usecase, all of the information yielded by compilation gets sent to a separate process than ide-backend-server (ghc). While it's nice to have a datatype for all the info yielded by a compilation, this seems wasteful from a performance perspective. It also means extending ide-backend with new features requires a lot more boilerplate than it ought to. 18 | 19 | 2. Another one of the reasons to have this multiple process architecture was to be able to accept mutations of the configuration of GHC (changing flags, etc), and intelligently either get GHC to update its flags or restart the ide-backend-server. This turned out to be very tricky, and we had lots of different issues and it's still imperfect. 20 | 21 | :memo: Let's just force a backend restart if you change ghc or RTS options. 22 | 23 | 3. With stack-ide, we ended up wrapping the pure API with another layer of datatypes for conversion to JSON. This meant the dataflow from the backend looked like: GHC types -> internal datatypes with explicit sharing -> byte serialized representation sent to ide-backend user -> public datatypes with sharing reified -> ide-backend function call -> stack-ide json datatype 24 | 25 | :memo: Lets avoid a lot of layers. 26 | 27 | ## Flycheck 28 | 29 | 1. Works pretty well/reliably (for @bitemyapp anyway), but a bit slow. Basically fires off a `stack build` (or `cabal build`) or `hlint` from the command line and parses stdout. 30 | 2. Emacs-only 31 | 3. Easier to get working reliably than `ghc-mod` 32 | -------------------------------------------------------------------------------- /docs/CircleCI.md: -------------------------------------------------------------------------------- 1 | # CircleCI 2 | 3 | ## Jobs 4 | 5 | For each version of GHC supported, CircleCI will kick off a build that will build and test HIE for that version. 6 | Whenever a new stack-x.y.z is added, be sure to also add it to both the `workflow` and `jobs` sections of `config.yml`. 7 | 8 | In addition to the stack based jobs, there is also a job that builds HIE with `cabal new-build`. 9 | Currently tests are not run as there is an issue with cabal-helper-wrapper that prevents any ghc-mod tests from passing. 10 | 11 | ## Docker 12 | 13 | Each job is carried out in a Docker container built from https://github.com/alanz/haskell-dockerfiles/blob/master/haskell-hie-ci/Dockerfile 14 | 15 | ## Caching 16 | 17 | Since HIE takes a long time to build, CI caches things very liberally. 18 | Most importantly, the `~/.stack-work` directories for HIE as well as every submodule are cached before and after testing (This is so that if the build passes but the tests fail there is still something cached for the next build). 19 | 20 | ### Change detection 21 | 22 | Before restoring any cache, the CircleCI job creates three files and uses their checksum to detect any changes: 23 | 24 | 1. `all-cabal.txt` detects any changes to `.cabal` files (not in submodules or test data) 25 | 2. `stack-build.txt` detects any changes to the `stack-x.y.z` file 26 | 3. `resolver.txt` detects any changes to the stack resolver 27 | 28 | Each job will tries to restore the most specific cache avaialble for it, and fallback to a more general cache if not available: 29 | 30 | 31 | ```yaml 32 | - restore_cache: 33 | keys: 34 | - stack-cache-{{ .Environment.HIE_CACHE }}-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "stack-build.txt" }}-{{ checksum "all-cabal.txt" }} 35 | - stack-cache-{{ .Environment.HIE_CACHE }}-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "stack-build.txt" }} 36 | - stack-cache-{{ .Environment.HIE_CACHE }}-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "resolver.txt" }} 37 | ``` 38 | 39 | ## Invalidating the cache 40 | 41 | If you need to clear the cache on CircleCI, bump the `$HIE_CACHE` environment variable via the CircleCI web interface and rerun the workflow. 42 | -------------------------------------------------------------------------------- /docs/Design.md: -------------------------------------------------------------------------------- 1 | # This file is outdated. Newer doc is [here](https://github.com/haskell/haskell-ide-engine/blob/master/docs/Architecture.md) 2 | 3 | ## This file is intended to capture the design as it evolves 4 | 5 | At this point it is nothing but a sketch, to try and capture the things the may have been agreed so far. 6 | 7 | It is likely to be wrong/off base, but is intended to provide a concrete point for discussion to revolve around. 8 | 9 | 10 | ### Plugin Architecture 11 | 12 | For the initial phase, we will go for the simplest possible plugin model. 13 | This should be something like the following 14 | 15 | 1. `haskell-ide-engine` is intended to be built and operated by a single version 16 | of GHC at any one time. 17 | 18 | What this means is that although it may support compilation with different 19 | versions of GHC, we will stick to only needing one at any given time, to 20 | avoid any issues around linking/operating. 21 | 22 | The intention is that this is the same version of GHC that the project 23 | being edited in the IDE is using. 24 | 25 | In the modern `stack` environment this may be a bit restrictive, but otherwise 26 | it introduces too much complexity in the beginning. 27 | 28 | 2. A plugin is provided as a library that can be installed from hackage/stack 29 | 30 | This allows a plugin developer to be able to work independently of `haskell-ide-backend` 31 | but still easily expose features to multiple IDEs. 32 | 33 | The simplest way of doing this will be to expose a lightweight "types-only" library 34 | which both the plugin and `haskell-ide-engine` will use to describe the features provided. 35 | 36 | This library is provisionally called `haskell-ide-plugin-api`. Bikeshedding welcome. 37 | 38 | A similar approach is being followed in https://github.com/neovimhaskell/nvim-hs, which can 39 | be used as a model. 40 | 41 | 3. There will be no dynamic loading of plugins 42 | 43 | A plugin will be something that `haskell-ide-engine` lists in its cabal file as a dependency. 44 | 45 | From a project perspective, we will have an open policy in terms of accepting PRs 46 | to add new plugins. 47 | 48 | This is another simplifying restriction, which may be lifted later when we have 49 | more insight, and running code. 50 | 51 | ### communication with the IDE 52 | 53 | 1. The eventual goal is that there is a clear separation between the types/messages 54 | transferred from `haskell-ide-engine` to the specific IDE and the transport layer 55 | used for this communication. 56 | 57 | In practice this means that some will communicate via JSON over HTTP, others using 58 | MSGPACK, and so on. 59 | 60 | 2. The operating environment will initially be assumed to be one instance of `haskell-ide-engine` 61 | talking to one IDE 62 | 63 | This will probably be valid for all time. 64 | 65 | 3. The messages exchanged need to be able to support the Idris mode rich interface 66 | 67 | To start with this may be simply having a message definition scheme that is 68 | sufficiently flexible, as this design goal is to some extent in conflict with 69 | the goal of getting something going as quickly as possible, which would suggest 70 | re-using existing code in current IDEs. This code would have to change quite a bit 71 | to support the richer functionality. 72 | 73 | -------------------------------------------------------------------------------- /docs/HaskellX2018.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskell/haskell-ide-engine/d84b84322ccac81bf4963983d55cc4e6e98ad418/docs/HaskellX2018.pdf -------------------------------------------------------------------------------- /docs/IDE-Support-in-GHC-HIW-2017.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskell/haskell-ide-engine/d84b84322ccac81bf4963983d55cc4e6e98ad418/docs/IDE-Support-in-GHC-HIW-2017.pdf -------------------------------------------------------------------------------- /docs/Packages.md: -------------------------------------------------------------------------------- 1 | # Packages 2 | 3 | ``` 4 | +----------------------------+ 5 | | | 6 | | haskell-ide-engine | 7 | | | 8 | | +------------------------+ | +------------------+ 9 | | | | | | | 10 | | | haskell-ide-engine-api | +----> haskell-lsp-test | 11 | | | | | | | 12 | | +------------------------+ | +-+----------------+ 13 | | | | 14 | +--------------------+-------+ | 15 | | | 16 | | | 17 | +----v--------------v---+ 18 | | | 19 | | haskell-lsp | 20 | | | 21 | | +-------------------+ | 22 | | | | | 23 | | | haskell-lsp-types | | 24 | | | | | 25 | | +-------------------+ | 26 | | | 27 | +-----------------------+ 28 | 29 | ``` 30 | 31 | HIE is built upon various separate repositories and packages: 32 | 33 | ## [haskell-lsp](https://github.com/alanz/haskell-lsp) 34 | Provides core functions for running a LSP server: 35 | - Sending messages 36 | - Parsing and receiving messages to various handlers 37 | - Mirroring client documents in a virtual file system (VFS) 38 | 39 | ### haskell-lsp-types 40 | A separate package within haskell-lsp that provides all the types as described in the specification. 41 | Includes lenses and some helper functions for converting between types. 42 | The separate package prevents unnecessary rebuilds of the template haskell files (which can take a long time) when working on haskell-ide-engine or haskell-lsp. 43 | 44 | ## [haskell-ide-engine](https://github.com/haskell/haskell-ide-engine) 45 | An executable server that routes LSP requests to various tools in the haskell ecosystem. 46 | Builds on top of haskell-lsp. 47 | Uses plugins to connect the tools into the server. 48 | Add plugin functionality in the `plugins` directory, and then hook it up to an appropriate LSP feature in `LspStdio.hs`. 49 | 50 | ### hie-plugin-api 51 | Types, monads and functions for the plugins in `haskell-ide-engine`. 52 | 53 | ## haskell-lsp-test 54 | A testing framework for LSP servers where scenarios can be captured or described in terms of messages. 55 | Used by HIE for functional tests. -------------------------------------------------------------------------------- /docs/Protocol.md: -------------------------------------------------------------------------------- 1 | # Protocol 2 | 3 | ## Language Server Protocol 4 | 5 | https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md 6 | 7 | Advantages include widespread tooling and IDE support, and standardization. 8 | 9 | Implemented in [LspStdio.hs](../src/Haskell/Ide/Engine/Transport/LspStdio.hs) 10 | 11 | ## Just use plain old HTTP for now 12 | 13 | For a first pass, until we know where any performance problems actually are, the nicest thing is to do plain HTTP with as stateless as possible of a protocol. It's unlikely any initial perf issues would have anything to do with the protocol, more likely to be the result of munging the code. 14 | 15 | ## JSON 16 | 17 | JSON has wide and popular support in a variety of languages. Supporting a uniform JSON representation will be a lot easier to manage for clients and the backend than JSON+sexprs+whatever. 18 | 19 | ## Ideas for dealing with asynchrony/blocking in clients that don't have threading/async 20 | 21 | ### Promises/continuation ids 22 | 23 | Return a promise id and let the client decide when to block on getting the response? 24 | 25 | `GET /type/?data=blah -> {"promise": 0}`, then `GET /promise/0` when you're ready for the answer. 26 | 27 | How does it work if there are other async events coming too, and/or it is a long running command so there is no knowledge in the front end of when it has finished? You perform multiple requests, you got: `get -> 1, get -> 2, get -> 3`. When you want answers, those callback ids in any order you like. Point is to uniquely (but temporarily) identify an ongoing computation across the wall. 28 | 29 | This is a bit like codata; it's a stretch, but bear with me! In total languages, if you have an indefinite stream of data, you have to keep giving control back to the caller rather than make them block indefinitely. You can either block or give them a chance to block on another continuation. 30 | 31 | 32 | #### Improvements on this 33 | 34 | - Let client assert a timeout. `timeout=5ms`, then if you don't have an answer within 5 ms, give them a new k id. 35 | 36 | - Probably let client pick the id so they don't have to snip it out of the reply. 37 | -------------------------------------------------------------------------------- /docs/Report-2017-07.md: -------------------------------------------------------------------------------- 1 | ## Haskell IDE Engine progress report for July 2017. 2 | 3 | ### What is Haskell IDE Engine? 4 | 5 | Not an IDE. 6 | 7 | It is a common point for people in the Haskell community to pool their efforts 8 | with respect to tooling. 9 | 10 | For tool writers, provide tools as a HIE plugin, so it can be available on 11 | supported IDEs 12 | 13 | For IDE developers, integrate to HIE, and all the Haskell tools supported as 14 | plugins become available 15 | 16 | For users, it means the overall Haskell experience should improve. 17 | 18 | Currently, we are targeting the Language Server Protocol as the channel via 19 | which we talk to IDEs and editors. This would allow much broader IDE support. 20 | 21 | ### Important developments 22 | 23 | Zubin Duggal started work on a Summer of Haskell project to improve the LSP 24 | support in HIE and implement more of the protocol. 25 | 26 | Large portions of the HIE codebase have been refactored and rearchitectured 27 | with LSP support in mind. Plugins for brittany and hoogle have been implemented. 28 | 29 | A new plugin request and dispatcher system has been implemented, along with a new 30 | architecture for the loading and caching of TypecheckedModules from source, which 31 | are used to drive many queries and features like type information, document symbols, 32 | document highlights and go to definition. 33 | 34 | Technical details regarding these changes are described in [Architecture](Architecture.md). 35 | 36 | As of July 2017, HIE supports a large portion of the LSP. For the complete 37 | feature list, check the [README](../README.md). 38 | 39 | ### Current project focus 40 | 41 | HIE (with vscode support via a plugin) is ready for an alpha release. Currently, 42 | the focus is on bug fixing and hooking up already existing features in HIE to 43 | LSP, like Hoogle queries and HaRe refactorings, and also providing additional features 44 | via LSP Code Actions and Code Lenses 45 | 46 | If you have experience writing Typescript or developing Visual Studio Code extensions, 47 | your help is needed to improve the vscode hie extension. 48 | 49 | ### Contributors active in June and July 50 | Alan Zimmerman, 51 | Zubin Duggal, 52 | Lennart Spitzner 53 | 54 | ### Contributing 55 | 56 | Haskell IDE Engine needs volunteers like any other open source project. 57 | For more information see: 58 | 59 | https://github.com/haskell/haskell-ide-engine 60 | 61 | Also drop by our IRC channel: #haskell-ide-engine at irc.freenode.net. 62 | 63 | Thanks! 64 | -------------------------------------------------------------------------------- /docs/Wishlists.md: -------------------------------------------------------------------------------- 1 | From https://www.reddit.com/r/haskell/comments/3z0ukd/reflecting_on_haskells_2015_and_my_wishes_for_2016/cyimsnp 2 | 3 | ``` 4 | Off the top of my head, ordered approximately by importance: 5 | 6 | on-the-fly typechecking 7 | autocompletion 8 | documentation and type lookup; types also for compound expressions 9 | semi-automatic management of imports, dependencies and LANGUAGE pragmas 10 | auto-formatting 11 | jump-to-definition 12 | syntax highlighting that's actually correct and complete 13 | HLint-style suggestions 14 | profiling, testing and benchmarking integration 15 | 16 | Many of these features are already covered by existing tools, but either with unsatisfactory 17 | performance or not particularly well integrated. (No offense intended; I imagine that writing 18 | Haskell tooling is exceptionally hard.) 19 | 20 | If a majority of these features became a reality, that'd make me very happy indeed. Good luck 21 | to you venerable fighters for a better Haskell experience. 22 | ``` 23 | From https://wiki.haskell.org/IDEs 24 | 25 | This is a list of features that any Haskell IDE could or should have. Existing Haskell IDEs generally support some subset of these features. 26 | 27 | - Syntax highlighting (e.g. for Haskell, Cabal, Literate Haskell, Core, etc.) 28 | - Macros (e.g. inserting imports/aligning/sorting imports, aligning up text, transposing/switching/moving things around) 29 | - Type information (e.g. type at point, info at point, type of expression) 30 | - IntelliSense/completion (e.g. jump-to-definition, who-calls, calls-who, search by type, completion, etc.) 31 | - Project management (e.g. understanding of Cabal, configuration/building/installing, package sandboxing) 32 | - Interactive REPL (e.g. GHCi/Hugs interaction, expression evaluation and such) 33 | - Knowledge of Haskell in the GHCi/GHC side (e.g. understanding error types, the REPL, REPL objects, object inspection) 34 | - Indentation support (e.g. tab cycle, simple back-forward indentation, whole area indentation, structured editing, etc.) 35 | - Proper syntactic awareness of Haskell (e.g. with a proper parser and proper editor transpositions a la the structured editors of the 80s and Isabel et al) 36 | - Documentation support (e.g. ability to call up documentation of symbol or module, either in the editor, or in the browser) 37 | - Debugger support (e.g. stepping, breakpoints, etc.) 38 | - Refactoring support (e.g. symbol renaming, hlint, etc.) 39 | - Templates (e.g. snippets, Zen Coding type stuff, filling in all the cases of a case, etc.) 40 | -------------------------------------------------------------------------------- /docs/emacs.md: -------------------------------------------------------------------------------- 1 | ## How to use hie with emacs 2 | 3 | Emacs support is provided via [lsp-haskell](https://github.com/emacs-lsp/lsp-haskell) 4 | 5 | -------------------------------------------------------------------------------- /docs/hcar/2015.tex: -------------------------------------------------------------------------------- 1 | \documentclass[DIV16,twocolumn,10pt]{scrreprt} 2 | \usepackage{paralist} 3 | \usepackage{graphicx} 4 | \usepackage[final]{hcar} 5 | 6 | \begin{document} 7 | 8 | \begin{hcarentry}{haskell-ide-engine, a project for unifying IDE functionality} 9 | \report{Chris Allen} 10 | \status{Open source, just beginning} 11 | \participants{Alan Zimmerman, Michael Sloan, Gracjan Polak, Daniel Gr\"ober, others welcome} 12 | 13 | \makeheader 14 | 15 | \textit{haskell-ide} is a backend for driving the sort of features programmers 16 | expect out of IDE environments. Perhaps soon to be called 17 | \textit{haskell-ide-engine}, \textit{haskell-ide} is a project to unify tooling 18 | efforts into something different text editors, and indeed IDEs as well, could 19 | use to avoid duplication of effort. 20 | 21 | Features like type errors, linting, refactoring, and reformatting code are 22 | planned. People who are familiar with a particular part of the chain can 23 | focus their efforts there, knowing that the other parts will be handled by 24 | other components of the backend. Inspiration is being taken from the work the 25 | Idris community has done toward an interactive editing environment as well. This 26 | is a deliberately broad scope, the initial versions will be very limited at 27 | first. The sooner we can get started the sooner we will have something concrete 28 | to criticize and improve. 29 | 30 | Help is very much needed and wanted so if this is a problem that interests you, 31 | please pitch in! This is not a project just for a small inner circle. Anyone 32 | who wants to will be added to the project on github, address your request to 33 | @alanz or @hvr. 34 | 35 | \FurtherReading 36 | \url{https://github.com/haskell/haskell-ide-engine} \\ 37 | \url{https://mail.haskell.org/pipermail/haskell-cafe/2015-October/121875.html} \\ 38 | \url{https://www.fpcomplete.com/blog/2015/10/new-haskell-ide-repo} \\ 39 | \url{https://www.reddit.com/r/haskell/comments/3pt560/ann_haskellide_project/} \\ 40 | \url{https://www.reddit.com/r/haskell/comments/3qbgmo/fp_complete_the_new_haskellide_repo/} 41 | 42 | \end{hcarentry} 43 | 44 | \end{document} 45 | -------------------------------------------------------------------------------- /docs/hcar/2016.tex: -------------------------------------------------------------------------------- 1 | % haskellideengineaprojectf-Ch.tex 2 | \begin{hcarentry}{haskell-ide-engine, a project for unifying IDE functionality} 3 | \label{haskell-ide-engine} 4 | \report{Chris Allen}%11/15 5 | \status{Open source, just beginning} 6 | \participants{Alan Zimmerman, Moritz Kiefer, Michael Sloan, Gracjan Polak, Daniel Gr\"ober, 7 | others welcome} 8 | 9 | \makeheader 10 | 11 | \textit{haskell-ide-engine} is a backend for driving the sort of features programmers 12 | expect out of IDE environments. \textit{haskell-ide-engine} is a project to unify tooling 13 | efforts into something different text editors, and indeed IDEs as well, could 14 | use to avoid duplication of effort. 15 | 16 | 17 | There is basic support for getting type information and refactoring, 18 | more features including type errors, linting and reformatting are 19 | planned. People who are familiar with a particular part of the chain 20 | can focus their efforts there, knowing that the other parts will be 21 | handled by other components of the backend. Integration for Emacs and 22 | Leksah is available and should support the current features of the 23 | backend. \texttt{haskell-ide-engine} also has a REST API with Swagger UI. 24 | Inspiration is being taken from the work the Idris community has done 25 | toward an interactive editing environment as well. 26 | 27 | Help is very much needed and wanted so if this is a problem that interests you, 28 | please pitch in! This is not a project just for a small inner circle. Anyone 29 | who wants to will be added to the project on github, address your request to 30 | @alanz. 31 | 32 | \FurtherReading 33 | \begin{compactitem} 34 | \item\url{https://github.com/haskell/haskell-ide-engine} 35 | \item\url{https://mail.haskell.org/pipermail/haskell-cafe/2015-October/121875.html} 36 | \item\url{https://www.fpcomplete.com/blog/2015/10/new-haskell-ide-repo} 37 | \item\url{https://www.reddit.com/r/haskell/comments/3pt560/ann_haskellide_project/} 38 | \item\url{https://www.reddit.com/r/haskell/comments/3qbgmo/fp_complete_the_new_haskellide_repo/} 39 | \end{compactitem} 40 | 41 | \end{hcarentry} 42 | -------------------------------------------------------------------------------- /docs/hcar/Makefile: -------------------------------------------------------------------------------- 1 | pdf: 2 | pdflatex 2015.tex -o haskell-ide-2015.pdf 3 | 4 | clean: 5 | rm -f *.log 6 | rm -f *.aux 7 | rm -f *.out 8 | -------------------------------------------------------------------------------- /docs/leksah.md: -------------------------------------------------------------------------------- 1 | ## How to use hie with Leksah 2 | 3 | This document is a work in progress, as is the Leksah integration. 4 | 5 | ### Getting started 6 | 7 | ```bash 8 | git clone https://github.com/haskell/haskell-ide-engine.git 9 | cd haskell-ide-engine 10 | stack install 11 | ``` 12 | 13 | This will put the `hie` executable into `$HOME/.local/bin/hie`. 14 | 15 | Get Leksah sources from the hie-integration branch (https://github.com/Leksah/Leksah/tree/hie_integration) and build them. 16 | This branch has a dependency on hie-base, one of the submodules of haskell-ide-engine. So one way to build things is to add the directory where you cloned the hie-base sources to the Leksah sandbox or stack file. 17 | 18 | Once Leksah is built, you can start it normally. Then go to `Tools -> Preferences -> Helper Programs` and check the `use haskell-ide-engine` box, and fill in the path to the executable (`$HOME/.local/bin/hie`). 19 | 20 | ### Usage 21 | 22 | Once the haskell-ide-engine path set in the preferences, the following actions are available: 23 | 24 | - Type: will use the `ghcmod:type` command to display the type of the selected expression (no need to have a GHCi session running in Leksah) 25 | - Info: will use the `ghcmod:info` command to display information of the selected expression 26 | - Refactor: a few refactorings are available, provided by the hie HaRe plugin. Some like rename or dupdef will ask for the new name. Running the refactoring currently replaces the whole source contents. 27 | 28 | ### Troubleshooting 29 | 30 | Some messages are dumped to the Leksah log, so run Leksah in debug mode to see them. 31 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. haskell-ide-engine documentation master file, created by 2 | sphinx-quickstart on Wed Dec 23 20:37:57 2015. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to haskell-ide-engine's documentation! 7 | ============================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | plugins/index 15 | 16 | Indices and tables 17 | ================== 18 | 19 | * :ref:`genindex` 20 | * :ref:`modindex` 21 | * :ref:`search` 22 | -------------------------------------------------------------------------------- /hie-plugin-api/Haskell/Ide/Engine/Context.hs: -------------------------------------------------------------------------------- 1 | module Haskell.Ide.Engine.Context where 2 | 3 | import Data.Generics 4 | import Language.Haskell.LSP.Types 5 | import qualified GHC 6 | import Haskell.Ide.Engine.GhcCompat (GhcPs) -- for GHC 8.2.2 7 | import Haskell.Ide.Engine.PluginUtils 8 | import Control.Applicative ( (<|>) ) 9 | 10 | -- | A context of a declaration in the program 11 | -- e.g. is the declaration a type declaration or a value declaration 12 | -- Used for determining which code completions to show 13 | -- TODO: expand this with more contexts like classes or instances for 14 | -- smarter code completion 15 | data Context = TypeContext 16 | | ValueContext 17 | | ModuleContext String -- ^ module context with module name 18 | | ImportContext String -- ^ import context with module name 19 | | ImportListContext String -- ^ import list context with module name 20 | | ImportHidingContext String -- ^ import hiding context with module name 21 | | ExportContext -- ^ List of exported identifiers from the current module 22 | deriving (Show, Eq) 23 | 24 | -- | Generates a map of where the context is a type and where the context is a value 25 | -- i.e. where are the value decls and the type decls 26 | getContext :: Position -> GHC.ParsedModule -> Maybe Context 27 | getContext pos pm 28 | | Just (GHC.L (GHC.RealSrcSpan r) modName) <- moduleHeader 29 | , pos `isInsideRange` r 30 | = Just (ModuleContext (GHC.moduleNameString modName)) 31 | 32 | | Just (GHC.L (GHC.RealSrcSpan r) _) <- exportList 33 | , pos `isInsideRange` r 34 | = Just ExportContext 35 | 36 | | Just ctx <- something (Nothing `mkQ` go `extQ` goInline) decl 37 | = Just ctx 38 | 39 | | Just ctx <- something (Nothing `mkQ` importGo) imports 40 | = Just ctx 41 | 42 | | otherwise 43 | = Nothing 44 | 45 | where decl = GHC.hsmodDecls $ GHC.unLoc $ GHC.pm_parsed_source pm 46 | moduleHeader = GHC.hsmodName $ GHC.unLoc $ GHC.pm_parsed_source pm 47 | exportList = GHC.hsmodExports $ GHC.unLoc $ GHC.pm_parsed_source pm 48 | imports = GHC.hsmodImports $ GHC.unLoc $ GHC.pm_parsed_source pm 49 | 50 | go :: GHC.LHsDecl GhcPs -> Maybe Context 51 | go (GHC.L (GHC.RealSrcSpan r) GHC.SigD {}) 52 | | pos `isInsideRange` r = Just TypeContext 53 | | otherwise = Nothing 54 | go (GHC.L (GHC.RealSrcSpan r) GHC.ValD {}) 55 | | pos `isInsideRange` r = Just ValueContext 56 | | otherwise = Nothing 57 | go _ = Nothing 58 | 59 | goInline :: GHC.LHsType GhcPs -> Maybe Context 60 | goInline (GHC.L (GHC.RealSrcSpan r) _) 61 | | pos `isInsideRange` r = Just TypeContext 62 | | otherwise = Nothing 63 | goInline _ = Nothing 64 | 65 | p `isInsideRange` r = sp <= p && p <= ep 66 | where (sp, ep) = unpackRealSrcSpan r 67 | 68 | importGo :: GHC.LImportDecl GhcPs -> Maybe Context 69 | importGo (GHC.L (GHC.RealSrcSpan r) impDecl) 70 | | pos `isInsideRange` r 71 | = importInline importModuleName (GHC.ideclHiding impDecl) 72 | <|> Just (ImportContext importModuleName) 73 | 74 | | otherwise = Nothing 75 | where importModuleName = GHC.moduleNameString $ GHC.unLoc $ GHC.ideclName impDecl 76 | 77 | importGo _ = Nothing 78 | 79 | importInline :: String -> Maybe (Bool, GHC.Located [GHC.LIE GhcPs]) -> Maybe Context 80 | importInline modName (Just (True, GHC.L (GHC.RealSrcSpan r) _)) 81 | | pos `isInsideRange` r = Just $ ImportHidingContext modName 82 | | otherwise = Nothing 83 | importInline modName (Just (False, GHC.L (GHC.RealSrcSpan r) _)) 84 | | pos `isInsideRange` r = Just $ ImportListContext modName 85 | | otherwise = Nothing 86 | importInline _ _ = Nothing 87 | 88 | -------------------------------------------------------------------------------- /hie-plugin-api/Haskell/Ide/Engine/GhcUtils.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ScopedTypeVariables #-} 2 | module Haskell.Ide.Engine.GhcUtils where 3 | 4 | import qualified Language.Haskell.LSP.Core as Core 5 | 6 | import qualified HscMain as G 7 | import Module 8 | import HscTypes 9 | import GHC 10 | import IOEnv as G 11 | import qualified Data.Text as T 12 | 13 | import HIE.Bios.Types (CradleError) 14 | 15 | import Haskell.Ide.Engine.PluginUtils (ErrorHandler(..)) 16 | 17 | -- Convert progress continuation to a messager 18 | toMessager :: (Core.Progress -> IO ()) -> G.Messager 19 | toMessager k _hsc_env (nk, n) _rc_reason ms = 20 | let prog = Core.Progress (Just (100 * fromIntegral nk / fromIntegral n)) (Just mod_name) 21 | mod_name = T.pack $ moduleNameString (moduleName (ms_mod ms)) 22 | in k prog 23 | 24 | -- Handlers for each type of error that ghc can throw 25 | errorHandlers :: (String -> m a) -> (HscTypes.SourceError -> m a) -> [ErrorHandler m a] 26 | errorHandlers onGhcError onSourceError = handlers 27 | where 28 | -- ghc throws GhcException, SourceError, GhcApiError and 29 | -- IOEnvFailure. hie-bios throws CradleError. 30 | handlers = 31 | [ ErrorHandler $ \(ex :: IOEnvFailure) -> 32 | onGhcError (show ex) 33 | , ErrorHandler $ \(ex :: GhcApiError) -> 34 | onGhcError (show ex) 35 | , ErrorHandler $ \(ex :: SourceError) -> 36 | onSourceError ex 37 | , ErrorHandler $ \(ex :: IOError) -> 38 | onGhcError (show ex) 39 | , ErrorHandler $ \(ex :: CradleError) -> 40 | onGhcError (show ex) 41 | , ErrorHandler $ \(ex :: GhcException) -> 42 | onGhcError (showGhcException ex "") 43 | ] 44 | -------------------------------------------------------------------------------- /hie-plugin-api/Haskell/Ide/Engine/Logger.hs: -------------------------------------------------------------------------------- 1 | module Haskell.Ide.Engine.Logger where 2 | 3 | import Control.Monad.IO.Class 4 | import System.Log.Logger 5 | 6 | logm :: MonadIO m => String -> m () 7 | logm s = liftIO $ infoM "hie" s 8 | 9 | debugm :: MonadIO m => String -> m () 10 | debugm s = liftIO $ debugM "hie" s 11 | 12 | warningm :: MonadIO m => String -> m () 13 | warningm s = liftIO $ warningM "hie" s 14 | 15 | errorm :: MonadIO m => String -> m () 16 | errorm s = liftIO $ errorM "hie" s 17 | -------------------------------------------------------------------------------- /hie-plugin-api/Haskell/Ide/Engine/MonadTypes.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleContexts #-} 2 | {-# LANGUAGE MultiParamTypeClasses #-} 3 | {-# LANGUAGE FlexibleInstances #-} 4 | {-# LANGUAGE ScopedTypeVariables #-} 5 | {-# LANGUAGE GADTs #-} 6 | {-# LANGUAGE RankNTypes #-} 7 | {-# LANGUAGE TypeSynonymInstances #-} 8 | 9 | -- | IdeGhcM and associated types 10 | module Haskell.Ide.Engine.MonadTypes 11 | ( 12 | -- * All the good types 13 | module Haskell.Ide.Engine.MultiThreadState 14 | , module Haskell.Ide.Engine.PluginsIdeMonads 15 | , module Haskell.Ide.Engine.GhcModuleCache 16 | , module Haskell.Ide.Engine.ModuleCache 17 | ) where 18 | 19 | import Haskell.Ide.Engine.MultiThreadState 20 | import Haskell.Ide.Engine.PluginsIdeMonads 21 | import Haskell.Ide.Engine.GhcModuleCache 22 | import Haskell.Ide.Engine.ModuleCache 23 | -------------------------------------------------------------------------------- /hie-plugin-api/Haskell/Ide/Engine/MultiThreadState.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE MultiParamTypeClasses #-} 2 | {-# LANGUAGE FunctionalDependencies #-} 3 | {-# LANGUAGE TypeSynonymInstances #-} 4 | {-# LANGUAGE FlexibleInstances #-} 5 | module Haskell.Ide.Engine.MultiThreadState 6 | ( MultiThreadState 7 | , readMTState 8 | , modifyMTState 9 | , runMTState 10 | , MonadMTState(..) 11 | ) where 12 | 13 | import Control.Concurrent.STM 14 | import Control.Monad.Reader 15 | 16 | -- --------------------------------------------------------------------- 17 | 18 | type MultiThreadState s = ReaderT (TVar s) IO 19 | 20 | readMTState :: MultiThreadState s s 21 | readMTState = ask >>= liftIO . readTVarIO 22 | 23 | modifyMTState :: (s -> s) -> MultiThreadState s () 24 | modifyMTState f = do 25 | tvar <- ask 26 | liftIO $ atomically $ modifyTVar' tvar f 27 | 28 | runMTState :: MultiThreadState s a -> s -> IO a 29 | runMTState m s = do 30 | tv <- newTVarIO s 31 | runReaderT m tv 32 | 33 | class MonadIO m => MonadMTState s m | m -> s where 34 | readMTS :: m s 35 | modifyMTS :: (s -> s) -> m () 36 | 37 | instance MonadMTState s (MultiThreadState s) where 38 | readMTS = readMTState 39 | modifyMTS = modifyMTState 40 | -------------------------------------------------------------------------------- /hie-plugin-api/Haskell/Ide/Engine/PluginApi.hs: -------------------------------------------------------------------------------- 1 | -- | This module provides an API that software intended to be 2 | -- integrated into HIE can use, so that they can make use of the 3 | -- shared BIOS features. 4 | 5 | {- 6 | -- Stuff used in HaRe currently 7 | Options(..) 8 | defaultOptions 9 | GmModuleGraph(..) 10 | ModulePath(..) 11 | GmComponent(..) 12 | GmComponentType(..) 13 | 14 | CachedInfo(..) 15 | HasGhcModuleCache(..) 16 | IdeGhcM 17 | 18 | cabalModuleGraphs 19 | filePathToUri 20 | makeRevRedirMapFunc 21 | 22 | MonadIO(..) 23 | ifCachedModule 24 | runIdeGhcMBare 25 | setTypecheckedModule 26 | -} 27 | 28 | 29 | module Haskell.Ide.Engine.PluginApi 30 | ( 31 | -- * IDE monads 32 | HIE.IdeState(..) 33 | , HIE.IdeGhcM 34 | , HIE.runIdeGhcM 35 | , HIE.runActionWithContext 36 | , HIE.IdeM 37 | , HIE.runIdeM 38 | , HIE.IdeDeferM 39 | , HIE.MonadIde 40 | , HIE.iterT 41 | , HIE.LiftsToGhc(..) 42 | , HIE.HasGhcModuleCache(..) 43 | -- , HIE.cabalModuleGraphs 44 | , HIE.makeRevRedirMapFunc 45 | 46 | -- * Using the HIE module cache etc 47 | , HIE.setTypecheckedModule 48 | , HIE.Diagnostics 49 | , HIE.AdditionalErrs 50 | , LSP.filePathToUri 51 | , LSP.uriToFilePath 52 | , LSP.Uri 53 | , HIE.ifCachedModule 54 | , HIE.CachedInfo(..) 55 | , HIE.IdeResult(..) 56 | 57 | -- * used for tests in HaRe 58 | , BiosLogLevel 59 | , BiosOptions 60 | , defaultOptions 61 | , HIE.BIOSVerbosity(..) 62 | , HIE.CradleOpts(..) 63 | , emptyIdePlugins 64 | , emptyIdeState 65 | ) where 66 | 67 | 68 | 69 | import qualified Haskell.Ide.Engine.Ghc as HIE 70 | import qualified Haskell.Ide.Engine.GhcModuleCache as HIE (CachedInfo(..),HasGhcModuleCache(..),emptyModuleCache) 71 | import qualified Haskell.Ide.Engine.ModuleCache as HIE (ifCachedModule,runActionWithContext ) 72 | import qualified Haskell.Ide.Engine.PluginsIdeMonads as HIE 73 | import qualified Language.Haskell.LSP.Types as LSP ( filePathToUri, uriToFilePath, Uri ) 74 | import qualified HIE.Bios.Types as HIE 75 | 76 | defaultOptions :: HIE.CradleOpts 77 | defaultOptions = HIE.defaultCradleOpts 78 | type BiosLogLevel = HIE.BIOSVerbosity 79 | 80 | type BiosOptions = HIE.CradleOpts 81 | 82 | emptyIdePlugins :: HIE.IdePlugins 83 | emptyIdePlugins = HIE.IdePlugins mempty 84 | 85 | emptyIdeState :: HIE.IdeState 86 | emptyIdeState = HIE.IdeState HIE.emptyModuleCache mempty mempty Nothing 87 | -------------------------------------------------------------------------------- /hie-plugin-api/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016, TBD 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following 14 | disclaimer in the documentation and/or other materials provided 15 | with the distribution. 16 | 17 | * Neither the name of Alan Zimmerman nor the names of other 18 | contributors may be used to endorse or promote products derived 19 | from this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /hie-plugin-api/hie-plugin-api.cabal: -------------------------------------------------------------------------------- 1 | name: hie-plugin-api 2 | version: 1.4 3 | synopsis: Haskell IDE API for plugin communication 4 | description: Please see README.md 5 | license: BSD3 6 | license-file: LICENSE 7 | author: Many,TBD when we release 8 | maintainer: alan.zimm@gmail.com (for now) 9 | copyright: 2015 TBD 10 | category: Web 11 | build-type: Simple 12 | -- extra-source-files: 13 | -- cabal-helper for cabal 2.2/GHC 8.4 needs a cabal version >= 2 14 | cabal-version: >=2.0 15 | 16 | flag pedantic 17 | Description: Enable -Werror 18 | Default: False 19 | Manual: True 20 | 21 | library 22 | exposed-modules: 23 | Haskell.Ide.Engine.ArtifactMap 24 | Haskell.Ide.Engine.Compat 25 | Haskell.Ide.Engine.Cradle 26 | Haskell.Ide.Engine.GhcCompat 27 | Haskell.Ide.Engine.GhcUtils 28 | Haskell.Ide.Engine.Config 29 | Haskell.Ide.Engine.Context 30 | Haskell.Ide.Engine.Ghc 31 | Haskell.Ide.Engine.GhcModuleCache 32 | Haskell.Ide.Engine.Logger 33 | Haskell.Ide.Engine.ModuleCache 34 | Haskell.Ide.Engine.MonadFunctions 35 | Haskell.Ide.Engine.MonadTypes 36 | Haskell.Ide.Engine.MultiThreadState 37 | Haskell.Ide.Engine.PluginApi 38 | Haskell.Ide.Engine.PluginUtils 39 | Haskell.Ide.Engine.PluginsIdeMonads 40 | Haskell.Ide.Engine.TypeMap 41 | build-depends: base >= 4.9 && < 5 42 | , Diff 43 | , aeson 44 | , bytestring-trie 45 | , bytestring 46 | , cryptohash-sha1 47 | , constrained-dynamic 48 | , containers 49 | , data-default 50 | , directory 51 | , filepath 52 | , fingertree 53 | , free 54 | , ghc 55 | , hie-bios 56 | , cabal-helper 57 | , haskell-lsp == 0.20.* 58 | , hslogger 59 | , unliftio 60 | , unliftio-core ^>= 0.2.0.1 61 | , monad-control 62 | , mtl 63 | , process 64 | , sorted-list 65 | , stm 66 | , syb 67 | , text 68 | , transformers 69 | , unordered-containers 70 | , transformers-base 71 | , yaml >= 0.8.11 72 | if os(windows) 73 | build-depends: Win32 74 | else 75 | build-depends: unix 76 | ghc-options: -Wall 77 | if flag(pedantic) 78 | ghc-options: -Werror 79 | default-language: Haskell2010 80 | -------------------------------------------------------------------------------- /hie.yaml.cbl: -------------------------------------------------------------------------------- 1 | # This is a sample hie.yaml file for opening haskell-ide-engine in 2 | # hie, using cabal as the build system. 3 | # To use is, copy it to a file called 'hie.yaml' 4 | 5 | cradle: 6 | cabal: 7 | - path: "./hie-plugin-api/Haskell" 8 | component: "lib:hie-plugin-api" 9 | 10 | - path: "./test/dispatcher/" 11 | component: "haskell-ide-engine:dispatcher-test" 12 | 13 | - path: "./test/functional/" 14 | component: "haskell-ide-engine:func-test" 15 | 16 | - path: "./test/unit/" 17 | component: "haskell-ide-engine:unit-test" 18 | 19 | - path: "./test/plugin-dispatcher/" 20 | component: "haskell-ide-engine:plugin-dispatcher-test" 21 | 22 | - path: "./test/wrapper/" 23 | component: "haskell-ide-engine:wrapper-test" 24 | 25 | - path: "./test/utils/" 26 | component: "haskell-ide-engine:hie-test-utils" 27 | 28 | - path: "./app/MainHie.hs" 29 | component: "haskell-ide-engine:hie" 30 | 31 | - path: "./app/HieWrapper.hs" 32 | component: "haskell-ide-engine:hie-wrapper" 33 | 34 | - path: "./" 35 | component: "lib:haskell-ide-engine" 36 | -------------------------------------------------------------------------------- /hie.yaml.stack: -------------------------------------------------------------------------------- 1 | # This is a sample hie.yaml file for opening haskell-ide-engine in 2 | # hie, using stack as the build system. 3 | # To use is, copy it to a file called 'hie.yaml' 4 | 5 | cradle: 6 | stack: 7 | - path: "./hie-plugin-api/" 8 | component: "hie-plugin-api:lib" 9 | 10 | - path: "./test/dispatcher/" 11 | component: "haskell-ide-engine:test:dispatcher-test" 12 | 13 | - path: "./test/functional/" 14 | component: "haskell-ide-engine:test:func-test" 15 | 16 | - path: "./test/unit/" 17 | component: "haskell-ide-engine:test:unit-test" 18 | 19 | - path: "./test/plugin-dispatcher/" 20 | component: "haskell-ide-engine:test:plugin-dispatcher-test" 21 | 22 | - path: "./test/wrapper/" 23 | component: "haskell-ide-engine:test:wrapper-test" 24 | 25 | # This target does not currently work (stack 2.1.3) 26 | - path: "./test/utils/" 27 | component: "haskell-ide-engine:lib:hie-test-utils" 28 | 29 | - path: "./app/MainHie.hs" 30 | component: "haskell-ide-engine:exe:hie" 31 | 32 | - path: "./app/HieWrapper.hs" 33 | component: "haskell-ide-engine:exe:hie-wrapper" 34 | 35 | - path: "./" 36 | component: "haskell-ide-engine:lib" 37 | -------------------------------------------------------------------------------- /install.hs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env stack 2 | {- stack 3 | runghc 4 | --stack-yaml=install/shake.yaml 5 | --package hie-install 6 | -} 7 | {- cabal: 8 | build-depends: 9 | base 10 | , hie-install 11 | -} 12 | -- call as: 13 | -- * `cabal v2-run install.hs --project-file install/shake.project ` 14 | -- * `stack install.hs ` 15 | 16 | -- TODO: set `shake.project` in cabal-config above, when supported 17 | -- (see https://github.com/haskell/cabal/issues/6353) 18 | 19 | import HieInstall (defaultMain) 20 | 21 | main = defaultMain 22 | -------------------------------------------------------------------------------- /install/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /install/cabal.project: -------------------------------------------------------------------------------- 1 | packages: 2 | ./ 3 | -------------------------------------------------------------------------------- /install/hie-install.cabal: -------------------------------------------------------------------------------- 1 | name: hie-install 2 | version: 0.8.1.0 3 | synopsis: Install the haskell-ide-engine 4 | license: BSD3 5 | author: Many, TBD when we release 6 | maintainer: samuel.pilz@posteo.net 7 | copyright: 2019 8 | build-type: Simple 9 | cabal-version: >=2.0 10 | 11 | library 12 | hs-source-dirs: src 13 | exposed-modules: HieInstall 14 | other-modules: BuildSystem 15 | , Stack 16 | , Version 17 | , Cabal 18 | , Print 19 | , Env 20 | , Help 21 | build-depends: base >= 4.9 && < 5 22 | , shake >= 0.16.4 && < 0.19 23 | , directory 24 | , filepath 25 | , extra 26 | , text 27 | default-extensions: LambdaCase 28 | , TupleSections 29 | , RecordWildCards 30 | default-language: Haskell2010 31 | 32 | if flag(run-from-stack) 33 | cpp-options: -DRUN_FROM_STACK 34 | else 35 | build-depends: cabal-install-parsers 36 | 37 | flag run-from-stack 38 | description: Inform the application that it is run from stack 39 | default: False 40 | manual: True 41 | -------------------------------------------------------------------------------- /install/shake.project: -------------------------------------------------------------------------------- 1 | packages: 2 | install/ 3 | -------------------------------------------------------------------------------- /install/shake.yaml: -------------------------------------------------------------------------------- 1 | # Used to provide a different environment for the shake build script 2 | resolver: lts-14.27 # last lts GHC 8.6.5 3 | # resolver: lts-15.7 # lts GHC 8.8.3 4 | # resolver: lts-15.3 # last lts GHC 8.8.2 5 | # resolver: lts-13.19 # last lts GHC 8.6.4 6 | # resolver: lts-12.26 # last lts GHC 8.4.4 7 | # resolver: lts-12.14 # last lts GHC 8.4.3 8 | # resolver: nightly-2018-05-30 # last nightly for GHC 8.4.2 9 | packages: 10 | - . 11 | 12 | extra-deps: 13 | - shake-0.18.5 14 | # for resolvers with ghc < 8.6 15 | # - shake-0.17 16 | - unix-time-0.4.7 17 | 18 | 19 | nix: 20 | packages: [ zlib ] 21 | 22 | flags: 23 | hie-install: 24 | run-from-stack: true 25 | -------------------------------------------------------------------------------- /install/src/BuildSystem.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | 3 | module BuildSystem where 4 | 5 | buildSystem :: String 6 | buildSystem = 7 | #if RUN_FROM_STACK 8 | "stack" 9 | #else 10 | "cabal" 11 | #endif 12 | 13 | isRunFromStack :: Bool 14 | isRunFromStack = buildSystem == "stack" 15 | 16 | isRunFromCabal :: Bool 17 | isRunFromCabal = buildSystem == "cabal" 18 | -------------------------------------------------------------------------------- /install/src/HieInstall.hs: -------------------------------------------------------------------------------- 1 | module HieInstall where 2 | 3 | import Development.Shake 4 | import Control.Monad 5 | import System.Environment ( unsetEnv ) 6 | 7 | import BuildSystem 8 | import Stack 9 | import Cabal 10 | import Version 11 | import Env 12 | import Help 13 | 14 | defaultMain :: IO () 15 | defaultMain = do 16 | -- unset GHC_PACKAGE_PATH for cabal 17 | unsetEnv "GHC_PACKAGE_PATH" 18 | 19 | -- used for cabal-based targets 20 | ghcPaths <- findInstalledGhcs 21 | let cabalVersions = map fst ghcPaths 22 | 23 | -- used for stack-based targets 24 | stackVersions <- getHieVersions 25 | 26 | let versions = if isRunFromStack then stackVersions else cabalVersions 27 | 28 | let toolsVersions = BuildableVersions stackVersions cabalVersions 29 | 30 | let latestVersion = last versions 31 | 32 | shakeArgs shakeOptions { shakeFiles = "_build" } $ do 33 | 34 | shakeOptionsRules <- getShakeOptionsRules 35 | 36 | let verbosityArg = if isRunFromStack then Stack.getVerbosityArg else Cabal.getVerbosityArg 37 | 38 | let args = [verbosityArg (shakeVerbosity shakeOptionsRules)] 39 | 40 | phony "show-options" $ do 41 | putNormal $ "Options:" 42 | putNormal $ " Verbosity level: " ++ show (shakeVerbosity shakeOptionsRules) 43 | 44 | want ["short-help"] 45 | -- general purpose targets 46 | phony "submodules" updateSubmodules 47 | phony "short-help" shortHelpMessage 48 | phony "help" (helpMessage toolsVersions) 49 | 50 | phony "check" (if isRunFromStack then checkStack args else checkCabal_ args) 51 | 52 | phony "data" $ do 53 | need ["show-options"] 54 | need ["submodules"] 55 | need ["check"] 56 | if isRunFromStack then stackBuildData args else cabalBuildData args 57 | 58 | forM_ 59 | versions 60 | (\version -> phony ("hie-" ++ version) $ do 61 | need ["show-options"] 62 | need ["submodules"] 63 | need ["check"] 64 | if isRunFromStack then 65 | stackInstallHieWithErrMsg (Just version) args 66 | else 67 | cabalInstallHie version args 68 | ) 69 | 70 | unless (null versions) $ do 71 | phony "latest" (need ["hie-" ++ latestVersion]) 72 | phony "hie" (need ["data", "latest"]) 73 | 74 | -- stack specific targets 75 | -- Default `stack.yaml` uses ghc-8.8.2 and we can't build hie in windows 76 | -- TODO: Enable for windows when it uses ghc-8.8.3 77 | when (isRunFromStack && not isWindowsSystem) $ 78 | phony "dev" $ do 79 | need ["show-options"] 80 | stackInstallHieWithErrMsg Nothing args 81 | 82 | -- cabal specific targets 83 | when isRunFromCabal $ do 84 | -- It throws an error if there is no ghc in $PATH 85 | checkInstalledGhcs ghcPaths 86 | phony "ghcs" $ showInstalledGhcs ghcPaths 87 | 88 | -- macos specific targets 89 | phony "icu-macos-fix" $ do 90 | need ["show-options"] 91 | need ["icu-macos-fix-install"] 92 | need ["icu-macos-fix-build"] 93 | 94 | phony "icu-macos-fix-install" (command_ [] "brew" ["install", "icu4c"]) 95 | phony "icu-macos-fix-build" $ mapM_ (flip buildIcuMacosFix $ args) versions 96 | 97 | 98 | buildIcuMacosFix :: VersionNumber -> [String] -> Action () 99 | buildIcuMacosFix version args = execStackWithGhc_ 100 | version $ 101 | [ "build" 102 | , "text-icu" 103 | , "--extra-lib-dirs=/usr/local/opt/icu4c/lib" 104 | , "--extra-include-dirs=/usr/local/opt/icu4c/include" 105 | ] ++ args 106 | 107 | -- | update the submodules that the project is in the state as required by the `stack.yaml` files 108 | updateSubmodules :: Action () 109 | updateSubmodules = do 110 | command_ [] "git" ["submodule", "sync"] 111 | command_ [] "git" ["submodule", "update", "--init"] 112 | -------------------------------------------------------------------------------- /install/src/Print.hs: -------------------------------------------------------------------------------- 1 | module Print where 2 | 3 | import Development.Shake 4 | import Control.Monad.IO.Class 5 | import Data.List ( dropWhileEnd 6 | ) 7 | import Data.Char ( isSpace ) 8 | 9 | -- | lift putStrLn to MonadIO 10 | printLine :: MonadIO m => String -> m () 11 | printLine = liftIO . putStrLn 12 | 13 | -- | print a line prepended with 4 spaces 14 | printLineIndented :: MonadIO m => String -> m () 15 | printLineIndented = printLine . (" " ++) 16 | 17 | embedInStars :: String -> String 18 | embedInStars str = 19 | let starsLine = "\n" <> replicate 80 '*' <> "\n" 20 | in starsLine <> str <> starsLine 21 | 22 | printInStars :: MonadIO m => String -> m () 23 | printInStars = liftIO . putStrLn . embedInStars 24 | 25 | 26 | -- | Trim whitespace of both ends of a string 27 | trim :: String -> String 28 | trim = dropWhileEnd isSpace . dropWhile isSpace 29 | 30 | -- | Trim the whitespace of the stdout of a command 31 | trimmedStdout :: Stdout String -> String 32 | trimmedStdout (Stdout s) = trim s 33 | 34 | type TargetDescription = (String, String) 35 | 36 | -- | Number of spaces the target name including whitespace should have. 37 | -- At least twenty, maybe more if target names are long. At most the length of the longest target plus five. 38 | space :: [(String,String)] -> Int 39 | space helpItems = maximum (20 : map ((+ 5) . length . fst) helpItems) 40 | 41 | -- | Show a target. 42 | -- Concatenates the target with its help message and inserts whitespace between them. 43 | showHelpItem :: Int -> (String,String) -> String 44 | showHelpItem spaces (helpItemKey, msg) = 45 | helpItemKey ++ replicate (spaces - length helpItemKey) ' ' ++ msg 46 | -------------------------------------------------------------------------------- /install/src/Version.hs: -------------------------------------------------------------------------------- 1 | module Version where 2 | 3 | import Data.Version ( Version 4 | , parseVersion 5 | , makeVersion 6 | , showVersion 7 | ) 8 | import Text.ParserCombinators.ReadP ( readP_to_S ) 9 | 10 | 11 | type VersionNumber = String 12 | type RequiredVersion = [Int] 13 | 14 | versionToString :: RequiredVersion -> String 15 | versionToString = showVersion . makeVersion 16 | 17 | -- | Parse a version-string into a version. Fails if the version-string is not valid 18 | parseVersionEx :: String -> Version 19 | parseVersionEx = fst . head . filter (("" ==) . snd) . readP_to_S parseVersion 20 | 21 | -- | Check that a given version-string is not smaller than the required version 22 | checkVersion :: RequiredVersion -> String -> Bool 23 | checkVersion required given = parseVersionEx given >= makeVersion required 24 | -------------------------------------------------------------------------------- /licenses/xmonad-contrib: -------------------------------------------------------------------------------- 1 | -- For the ExtensibleState module 2 | 3 | Copyright (c) The Xmonad Community 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 3. Neither the name of the author nor the names of his contributors 16 | may be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /logos/HIE_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /logos/HIE_logo_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskell/haskell-ide-engine/d84b84322ccac81bf4963983d55cc4e6e98ad418/logos/HIE_logo_1024.png -------------------------------------------------------------------------------- /logos/HIE_logo_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskell/haskell-ide-engine/d84b84322ccac81bf4963983d55cc4e6e98ad418/logos/HIE_logo_128.png -------------------------------------------------------------------------------- /logos/HIE_logo_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskell/haskell-ide-engine/d84b84322ccac81bf4963983d55cc4e6e98ad418/logos/HIE_logo_256.png -------------------------------------------------------------------------------- /logos/HIE_logo_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskell/haskell-ide-engine/d84b84322ccac81bf4963983d55cc4e6e98ad418/logos/HIE_logo_32.png -------------------------------------------------------------------------------- /logos/HIE_logo_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskell/haskell-ide-engine/d84b84322ccac81bf4963983d55cc4e6e98ad418/logos/HIE_logo_512.png -------------------------------------------------------------------------------- /logos/HIE_logo_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskell/haskell-ide-engine/d84b84322ccac81bf4963983d55cc4e6e98ad418/logos/HIE_logo_64.png -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | with (import {}); 2 | stdenv.mkDerivation { 3 | name = "haskell-ide-engine"; 4 | buildInputs = [ 5 | gmp 6 | zlib 7 | ncurses 8 | 9 | haskellPackages.cabal-install 10 | ]; 11 | src = null; 12 | shellHook = '' 13 | export LD_LIBRARY_PATH=${gmp}/lib:${zlib}/lib:${ncurses}/lib 14 | export PATH=$PATH:$HOME/.local/bin 15 | ''; 16 | } 17 | -------------------------------------------------------------------------------- /src/Haskell/Ide/Engine/Channel.hs: -------------------------------------------------------------------------------- 1 | module Haskell.Ide.Engine.Channel 2 | ( InChan 3 | , OutChan 4 | , newChan 5 | , newChanSTM 6 | , readChan 7 | , readChanSTM 8 | , writeChan 9 | , writeChanSTM 10 | ) 11 | where 12 | 13 | import qualified Control.Concurrent.STM.TChan as TChan 14 | import qualified Control.Concurrent.STM as STM 15 | 16 | -- | The writing end of a STM channel, only values of type 'a' can be written 17 | -- to the channel 18 | newtype InChan a = InChan (TChan.TChan a) 19 | 20 | -- | The reading end of a STM channel, values of type 'a' can be expected to 21 | -- be read. 22 | newtype OutChan a = OutChan (TChan.TChan a) 23 | 24 | -- | Returns the reading and writing ends of a channel able to trasmit values of 25 | -- a single given type 26 | newChan :: IO (InChan a, OutChan a) 27 | newChan = STM.atomically newChanSTM 28 | 29 | -- | STM version of 'newChan', useful for chaining many STM calls inside a single 30 | -- 'atomically' block. 31 | newChanSTM :: STM.STM (InChan a, OutChan a) 32 | newChanSTM = do 33 | chan <- TChan.newTChan 34 | return (InChan chan, OutChan chan) 35 | 36 | -- | Consumes and returns the next value of the given channel 37 | readChan :: OutChan a -> IO a 38 | readChan = STM.atomically . readChanSTM 39 | 40 | -- | STM version of 'readChan', useful for chaining many STM calls inside a single 41 | -- 'atomically' block. 42 | readChanSTM :: OutChan a -> STM.STM a 43 | readChanSTM (OutChan chan) = STM.readTChan chan 44 | 45 | -- | Writes a value to a channel. 46 | writeChan :: InChan a -> a -> IO () 47 | writeChan chan val = STM.atomically (writeChanSTM chan val) 48 | 49 | -- | STM version of 'writeChan', useful for chaining many STM calls inside a single 50 | -- 'atomically' block. 51 | writeChanSTM :: InChan a -> a -> STM.STM () 52 | writeChanSTM (InChan chan) = STM.writeTChan chan 53 | -------------------------------------------------------------------------------- /src/Haskell/Ide/Engine/CodeActions.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveAnyClass #-} 2 | {-# LANGUAGE DeriveGeneric #-} 3 | {-# LANGUAGE DuplicateRecordFields #-} 4 | {-# LANGUAGE OverloadedStrings #-} 5 | {-# LANGUAGE FlexibleContexts #-} 6 | module Haskell.Ide.Engine.CodeActions where 7 | 8 | import Control.Lens 9 | import Control.Monad.Reader 10 | import qualified Data.Aeson as J 11 | import Data.Maybe 12 | import Data.Foldable 13 | import qualified GHC.Generics as G 14 | import Haskell.Ide.Engine.Reactor 15 | import Haskell.Ide.Engine.Types 16 | import qualified Language.Haskell.LSP.Core as Core 17 | import qualified Language.Haskell.LSP.Types as J 18 | import qualified Language.Haskell.LSP.Types.Lens as J 19 | import qualified Language.Haskell.LSP.Types.Capabilities as C 20 | import Language.Haskell.LSP.VFS 21 | import Language.Haskell.LSP.Messages 22 | import Haskell.Ide.Engine.PluginsIdeMonads 23 | 24 | data FallbackCodeActionParams = 25 | FallbackCodeActionParams 26 | { fallbackWorkspaceEdit :: Maybe J.WorkspaceEdit 27 | , fallbackCommand :: Maybe J.Command 28 | } 29 | deriving (G.Generic, J.ToJSON, J.FromJSON) 30 | 31 | handleCodeActionReq :: TrackingNumber -> J.CodeActionRequest -> R () 32 | handleCodeActionReq tn req = do 33 | 34 | vfsFunc <- asksLspFuncs Core.getVirtualFileFunc 35 | docVersion <- fmap virtualFileVersion <$> liftIO (vfsFunc (J.toNormalizedUri docUri)) 36 | let docId = J.VersionedTextDocumentIdentifier docUri docVersion 37 | 38 | let getProvider p = pluginCodeActionProvider p <*> return (pluginId p) 39 | getProviders = do 40 | IdePlugins m <- getPlugins 41 | return $ IdeResultOk $ mapMaybe getProvider $ toList m 42 | 43 | providersCb providers = 44 | let reqs = map (\f -> lift (f docId range context)) providers 45 | in makeRequests reqs "code-actions" tn (req ^. J.id) (send . filter wasRequested . concat) 46 | 47 | makeRequest (IReq tn "code-actions" (req ^. J.id) providersCb getProviders) 48 | 49 | where 50 | params = req ^. J.params 51 | docUri = params ^. J.textDocument . J.uri 52 | range = params ^. J.range 53 | context = params ^. J.context 54 | 55 | wasRequested :: J.CodeAction -> Bool 56 | wasRequested ca 57 | | Nothing <- J.only context = True 58 | | Just (J.List allowed) <- J.only context 59 | , Just caKind <- ca ^. J.kind = caKind `elem` allowed 60 | | otherwise = False 61 | 62 | wrapCodeAction :: J.CodeAction -> R (Maybe J.CAResult) 63 | wrapCodeAction action = do 64 | 65 | (C.ClientCapabilities _ textDocCaps _ _) <- asksLspFuncs Core.clientCapabilities 66 | let literalSupport = textDocCaps >>= C._codeAction >>= C._codeActionLiteralSupport 67 | 68 | case literalSupport of 69 | Nothing -> do 70 | let cmdParams = [J.toJSON (FallbackCodeActionParams (action ^. J.edit) (action ^. J.command))] 71 | cmd <- mkLspCommand "hie" "fallbackCodeAction" (action ^. J.title) (Just cmdParams) 72 | return $ Just (J.CACommand cmd) 73 | Just _ -> return $ Just (J.CACodeAction action) 74 | 75 | send :: [J.CodeAction] -> R () 76 | send codeActions = do 77 | body <- J.List . catMaybes <$> mapM wrapCodeAction codeActions 78 | reactorSend $ RspCodeAction $ Core.makeResponseMessage req body 79 | 80 | -- TODO: make context specific commands for all sorts of things, such as refactorings 81 | -------------------------------------------------------------------------------- /src/Haskell/Ide/Engine/Options.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | module Haskell.Ide.Engine.Options where 3 | 4 | #if __GLASGOW_HASKELL__ < 808 5 | import Data.Monoid ((<>)) 6 | #endif 7 | import Data.Version (showVersion) 8 | import Haskell.Ide.Engine.Version 9 | import qualified Language.Haskell.LSP.Core as Core 10 | import Options.Applicative.Simple 11 | import qualified Paths_haskell_ide_engine as Meta 12 | import System.Directory 13 | import System.IO 14 | import qualified System.Log.Logger as L 15 | import Data.Foldable 16 | 17 | data ProjectLoadingOpts = ProjectLoadingOpts 18 | { optDryRun :: Bool 19 | , optFiles :: [FilePath] 20 | } deriving (Show, Eq) 21 | 22 | data RunMode = LspMode | ProjectLoadingMode ProjectLoadingOpts 23 | deriving (Show, Eq) 24 | 25 | data GlobalOpts = GlobalOpts 26 | { optDebugOn :: Bool 27 | , optLogFile :: Maybe String 28 | , projectRoot :: Maybe String 29 | , optBiosVerbose :: Bool 30 | , optCaptureFile :: Maybe FilePath 31 | , optExamplePlugin :: Bool 32 | , optMode :: RunMode 33 | } deriving (Show, Eq) 34 | 35 | -- | Introduced as the common prefix of app/HieWrapper.hs/main and app/MainHie.hs/main 36 | initApp :: String -> IO GlobalOpts 37 | initApp namedesc = do 38 | hSetBuffering stderr LineBuffering 39 | -- Parse the options and run 40 | (opts, ()) <- simpleOptions 41 | hieVersion 42 | namedesc 43 | "" 44 | optionParser 45 | empty 46 | Core.setupLogger (optLogFile opts) ["hie", "hie-bios"] 47 | $ if optDebugOn opts then L.DEBUG else L.INFO 48 | traverse_ setCurrentDirectory $ projectRoot opts 49 | return opts 50 | 51 | optionParser :: Parser GlobalOpts 52 | optionParser = numericVersion <*> compiler <*> globalOptsParser 53 | 54 | numericVersion :: Parser (a -> a) 55 | numericVersion = infoOption (showVersion Meta.version) 56 | (long "numeric-version" <> help "Show only version number") 57 | 58 | compiler :: Parser (a -> a) 59 | compiler = infoOption hieGhcDisplayVersion 60 | (long "compiler" <> help "Show only compiler and version supported") 61 | 62 | projectLoadingModeParser :: Parser RunMode 63 | projectLoadingModeParser = 64 | ProjectLoadingMode 65 | <$> (ProjectLoadingOpts 66 | <$> flag False True 67 | ( long "dry-run" 68 | <> help "Perform a dry-run of loading files. Only searches for Haskell source files to load. Does nothing if run as LSP server." 69 | ) 70 | <*> many 71 | ( argument str 72 | ( metavar "FILES..." 73 | <> help "Directories and Filepaths to load. Does nothing if run as LSP server.") 74 | ) 75 | ) 76 | 77 | globalOptsParser :: Parser GlobalOpts 78 | globalOptsParser = GlobalOpts 79 | <$> switch 80 | ( long "debug" 81 | <> short 'd' 82 | <> help "Generate debug output" 83 | ) 84 | <*> optional (strOption 85 | ( long "logfile" 86 | <> short 'l' 87 | <> metavar "LOGFILE" 88 | <> help "File to log to, defaults to stdout" 89 | )) 90 | <*> optional (strOption 91 | ( long "project-root" 92 | <> short 'r' 93 | <> metavar "PROJECTROOT" 94 | <> help "Root directory of project, defaults to cwd")) 95 | <*> (switch 96 | ( long "bios-verbose" 97 | <> help "enable verbose logging for hie-bios" 98 | ) 99 | <|> 100 | switch 101 | ( long "vomit" 102 | <> help "(deprecated) enable verbose logging for hie-bios" 103 | ) 104 | ) 105 | <*> optional (strOption 106 | ( long "capture" 107 | <> short 'c' 108 | <> metavar "CAPTUREFILE" 109 | <> help "File to capture the session to" 110 | )) 111 | <*> switch 112 | ( long "example" 113 | <> help "Enable Example2 plugin. Useful for developers only") 114 | <*> (flag' LspMode 115 | ( long "lsp" 116 | <> help "Start HIE as an LSP server. Otherwise it dumps debug info to stdout") 117 | <|> 118 | projectLoadingModeParser 119 | ) 120 | -------------------------------------------------------------------------------- /src/Haskell/Ide/Engine/Plugin/Floskell.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | -- | A flexible Haskell source code pretty printer. 4 | module Haskell.Ide.Engine.Plugin.Floskell 5 | ( floskellDescriptor 6 | ) 7 | where 8 | 9 | import Control.Monad.IO.Class (liftIO) 10 | import Data.Aeson (Value (Null)) 11 | import qualified Data.ByteString.Lazy as BS 12 | import qualified Data.Text as T 13 | import qualified Data.Text.Encoding as T 14 | import Floskell 15 | import Haskell.Ide.Engine.MonadTypes 16 | import Haskell.Ide.Engine.PluginUtils 17 | 18 | floskellDescriptor :: PluginId -> PluginDescriptor 19 | floskellDescriptor plId = PluginDescriptor 20 | { pluginId = plId 21 | , pluginName = "Floskell" 22 | , pluginDesc = "A flexible Haskell source code pretty printer." 23 | , pluginCommands = [] 24 | , pluginCodeActionProvider = Nothing 25 | , pluginDiagnosticProvider = Nothing 26 | , pluginHoverProvider = Nothing 27 | , pluginSymbolProvider = Nothing 28 | , pluginFormattingProvider = Just provider 29 | } 30 | 31 | -- | Format provider of Floskell. 32 | -- Formats the given source in either a given Range or the whole Document. 33 | -- If the provider fails an error is returned that can be displayed to the user. 34 | provider :: FormattingProvider 35 | provider contents uri typ _opts = 36 | pluginGetFile "Floskell: " uri $ \file -> do 37 | config <- liftIO $ findConfigOrDefault file 38 | let (range, selectedContents) = case typ of 39 | FormatText -> (fullRange contents, contents) 40 | FormatRange r -> (r, extractRange r contents) 41 | result = reformat config (Just file) (BS.fromStrict (T.encodeUtf8 selectedContents)) 42 | case result of 43 | Left err -> return $ IdeResultFail (IdeError PluginError (T.pack $ "floskellCmd: " ++ err) Null) 44 | Right new -> return $ IdeResultOk [TextEdit range (T.decodeUtf8 (BS.toStrict new))] 45 | 46 | -- | Find Floskell Config, user and system wide or provides a default style. 47 | -- Every directory of the filepath will be searched to find a user configuration. 48 | -- Also looks into places such as XDG_CONFIG_DIRECTORY. 49 | -- This function may not throw an exception and returns a default config. 50 | findConfigOrDefault :: FilePath -> IO AppConfig 51 | findConfigOrDefault file = do 52 | mbConf <- findAppConfigIn file 53 | case mbConf of 54 | Just confFile -> readAppConfig confFile 55 | Nothing -> 56 | let gibiansky = head (filter (\s -> styleName s == "gibiansky") styles) 57 | in return $ defaultAppConfig { appStyle = gibiansky } 58 | -------------------------------------------------------------------------------- /src/Haskell/Ide/Engine/Plugin/GhcMod.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {-# LANGUAGE DeriveGeneric #-} 3 | {-# LANGUAGE FlexibleContexts #-} 4 | {-# LANGUAGE OverloadedStrings #-} 5 | {-# LANGUAGE ScopedTypeVariables #-} 6 | {-# LANGUAGE TupleSections #-} 7 | {-# LANGUAGE TypeFamilies #-} 8 | module Haskell.Ide.Engine.Plugin.GhcMod 9 | ( 10 | ghcmodDescriptor 11 | 12 | -- * For tests 13 | -- , Bindings(..) 14 | -- , FunctionSig(..) 15 | -- , TypeDef(..) 16 | -- , TypeParams(..) 17 | -- , TypedHoles(..) -- only to keep the GHC 8.4 and below unused field warning happy 18 | -- , ValidSubstitutions(..) 19 | -- , extractHoleSubstitutions 20 | -- , extractMissingSignature 21 | -- , extractRenamableTerms 22 | -- , extractUnusedTerm 23 | -- , newTypeCmd 24 | -- , symbolProvider 25 | , splitCaseCmd 26 | ) where 27 | 28 | import Data.Aeson 29 | #if __GLASGOW_HASKELL__ < 808 30 | import Data.Monoid ((<>)) 31 | #endif 32 | import GHC.Generics 33 | import qualified Haskell.Ide.Engine.Ghc as HIE 34 | import Haskell.Ide.Engine.MonadTypes 35 | import qualified Haskell.Ide.Engine.Plugin.Generic as PG 36 | import qualified Haskell.Ide.Engine.Support.HieExtras as Hie 37 | 38 | -- --------------------------------------------------------------------- 39 | 40 | ghcmodDescriptor :: PluginId -> PluginDescriptor 41 | ghcmodDescriptor plId = PluginDescriptor 42 | { pluginId = plId 43 | , pluginName = "ghc-mod" 44 | , pluginDesc = "ghc-mod is a backend program to enrich Haskell programming " 45 | <> "in editors. It strives to offer most of the features one has come to expect " 46 | <> "from modern IDEs in any editor." 47 | , pluginCommands = 48 | [ 49 | -- This one is used in the dispatcher tests, and is a wrapper around what we are already using anyway 50 | PluginCommand "check" "check a file for GHC warnings and errors" checkCmd 51 | 52 | -- PluginCommand "info" "Look up an identifier in the context of FILE (like ghci's `:info')" infoCmd 53 | , PluginCommand "type" "Get the type of the expression under (LINE,COL)" PG.typeCmd 54 | 55 | -- This one is registered in the vscode plugin, for some reason 56 | , PluginCommand "casesplit" "Generate a pattern match for a binding under (LINE,COL)" splitCaseCmd 57 | ] 58 | , pluginCodeActionProvider = Nothing 59 | , pluginDiagnosticProvider = Nothing 60 | , pluginHoverProvider = Nothing 61 | , pluginSymbolProvider = Nothing 62 | , pluginFormattingProvider = Nothing 63 | } 64 | 65 | -- --------------------------------------------------------------------- 66 | 67 | -- checkCmd :: CommandFunc Uri (Diagnostics, AdditionalErrs) 68 | -- checkCmd = CmdSync setTypecheckedModule 69 | 70 | checkCmd :: Uri -> IdeGhcM (IdeResult (HIE.Diagnostics, HIE.AdditionalErrs)) 71 | checkCmd = HIE.setTypecheckedModule 72 | 73 | -- --------------------------------------------------------------------- 74 | 75 | splitCaseCmd :: Hie.HarePoint -> IdeGhcM (IdeResult WorkspaceEdit) 76 | splitCaseCmd (Hie.HP _uri _pos) 77 | = return (IdeResultFail (IdeError PluginError "splitCaseCmd not implemented" Null)) 78 | 79 | -- --------------------------------------------------------------------- 80 | 81 | customOptions :: Options 82 | customOptions = defaultOptions { fieldLabelModifier = camelTo2 '_' . drop 2} 83 | 84 | -- --------------------------------------------------------------------- 85 | 86 | data TypeParams = 87 | TP { tpIncludeConstraints :: Bool 88 | , tpFile :: Uri 89 | , tpPos :: Position 90 | } deriving (Eq,Show,Generic) 91 | 92 | instance FromJSON TypeParams where 93 | parseJSON = genericParseJSON customOptions 94 | instance ToJSON TypeParams where 95 | toJSON = genericToJSON customOptions 96 | 97 | -- -- --------------------------------------------------------------------- 98 | -------------------------------------------------------------------------------- /src/Haskell/Ide/Engine/Plugin/Package/Compat.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | module Haskell.Ide.Engine.Plugin.Package.Compat where 3 | 4 | #if MIN_VERSION_Cabal(2,2,0) 5 | #else 6 | import Control.Lens 7 | import Distribution.Types.GenericPackageDescription (GenericPackageDescription(GenericPackageDescription), ConfVar (..)) 8 | import Distribution.Types.UnqualComponentName (UnqualComponentName) 9 | import Distribution.Types.CondTree (CondTree) 10 | import Distribution.Types.Dependency (Dependency) 11 | import Distribution.Types.Benchmark (Benchmark(..)) 12 | import Distribution.Types.Library (Library, libBuildInfo) 13 | import Distribution.Types.TestSuite (TestSuite, testBuildInfo) 14 | import qualified Distribution.Types.Executable as E (Executable, buildInfo) 15 | import qualified Distribution.Types.BuildInfo as BI (BuildInfo(..)) 16 | #endif 17 | 18 | #if MIN_VERSION_Cabal(2,2,0) 19 | #else 20 | 21 | {-# ANN module ("HLint: ignore Avoid lambda" :: String) #-} 22 | 23 | condBenchmarks :: Lens' GenericPackageDescription [(UnqualComponentName, CondTree ConfVar [Dependency] Benchmark)] 24 | condBenchmarks f (GenericPackageDescription x1 x2 x3 x4 x5 x6 x7 x8) = fmap (\y1 -> GenericPackageDescription x1 x2 x3 x4 x5 x6 x7 y1) (f x8) 25 | {-# INLINE condBenchmarks #-} 26 | 27 | condExecutables :: Lens' GenericPackageDescription [(UnqualComponentName, CondTree ConfVar [Dependency] E.Executable)] 28 | condExecutables f (GenericPackageDescription x1 x2 x3 x4 x5 x6 x7 x8) = fmap (\y1 -> GenericPackageDescription x1 x2 x3 x4 x5 y1 x7 x8) (f x6) 29 | {-# INLINE condExecutables #-} 30 | 31 | condLibrary :: Lens' GenericPackageDescription (Maybe (CondTree ConfVar [Dependency] Library)) 32 | condLibrary f (GenericPackageDescription x1 x2 x3 x4 x5 x6 x7 x8) = fmap (\y1 -> GenericPackageDescription x1 x2 y1 x4 x5 x6 x7 x8) (f x3) 33 | {-# INLINE condLibrary #-} 34 | 35 | condSubLibraries :: Lens' GenericPackageDescription [(UnqualComponentName, CondTree ConfVar [Dependency] Library)] 36 | condSubLibraries f (GenericPackageDescription x1 x2 x3 x4 x5 x6 x7 x8) = fmap (\y1 -> GenericPackageDescription x1 x2 x3 y1 x5 x6 x7 x8) (f x4) 37 | {-# INLINE condSubLibraries #-} 38 | 39 | condTestSuites :: Lens' GenericPackageDescription [(UnqualComponentName, CondTree ConfVar [Dependency] TestSuite)] 40 | condTestSuites f (GenericPackageDescription x1 x2 x3 x4 x5 x6 x7 x8) = fmap (\y1 -> GenericPackageDescription x1 x2 x3 x4 x5 x6 y1 x8) (f x7) 41 | {-# INLINE condTestSuites #-} 42 | 43 | class HasBuildInfo a where 44 | buildInfo :: Lens' a BI.BuildInfo 45 | 46 | hsSourceDirs :: Lens' a [FilePath] 47 | hsSourceDirs = buildInfo . hsSourceDirs 48 | {-# INLINE hsSourceDirs #-} 49 | 50 | targetBuildDepends :: Lens' a [Dependency] 51 | targetBuildDepends = buildInfo . targetBuildDepends 52 | {-# INLINE targetBuildDepends #-} 53 | 54 | instance HasBuildInfo BI.BuildInfo where 55 | buildInfo = id 56 | 57 | hsSourceDirs f s = fmap (\x -> s { BI.hsSourceDirs = x }) (f (BI.hsSourceDirs s)) 58 | {-# INLINE hsSourceDirs #-} 59 | 60 | targetBuildDepends f s = fmap (\x -> s { BI.targetBuildDepends = x }) (f (BI.targetBuildDepends s)) 61 | {-# INLINE targetBuildDepends #-} 62 | 63 | instance HasBuildInfo E.Executable where 64 | buildInfo f l = (\x -> l { E.buildInfo = x }) <$> f (E.buildInfo l) 65 | 66 | instance HasBuildInfo Benchmark where 67 | buildInfo f (Benchmark x1 x2 x3) = fmap (\y1 -> Benchmark x1 x2 y1) (f x3) 68 | 69 | instance HasBuildInfo TestSuite where 70 | buildInfo f l = (\x -> l { testBuildInfo = x }) <$> f (testBuildInfo l) 71 | 72 | instance HasBuildInfo Library where 73 | buildInfo f l = (\x -> l { libBuildInfo = x }) <$> f (libBuildInfo l) 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /src/Haskell/Ide/Engine/Support/Fuzzy.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleContexts #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | 4 | -- | Forked from: Text.Fuzzy (MIT) 5 | -- Original Author: Joomy Korkut, http://github.com/joom/fuzzy 6 | -- Uses 'TextualMonoid' to be able to run on different types of strings. 7 | module Haskell.Ide.Engine.Support.Fuzzy where 8 | 9 | import Prelude hiding (filter, null) 10 | 11 | import Data.Char (toLower) 12 | import Data.List (sortOn) 13 | import Data.Maybe (isJust, mapMaybe) 14 | import Data.Ord 15 | 16 | import qualified Data.Monoid.Textual as T 17 | 18 | -- | Included in the return type of @'match'@ and @'filter'@. 19 | -- Contains the original value given, and the matching score. 20 | data Fuzzy t s = 21 | Fuzzy { original :: t 22 | , score :: Int 23 | } deriving (Show, Eq) 24 | 25 | -- | Returns the matched value and score. 26 | -- TODO: add more scoring factors (see Sublime's fuzzy algo) 27 | -- 28 | -- >>> match id True "fnt" "infinite" 29 | -- Just ("infinite", 3) 30 | -- 31 | -- >>> match fst False "hsk" ("Haskell", 1995) 32 | -- Just ("haskell", 5) 33 | -- 34 | match :: (T.TextualMonoid s) 35 | => (t -> s) -- ^ The function to extract the text from the container. 36 | -> Bool -- ^ Case sensitivity. 37 | -> s -- ^ Pattern. 38 | -> t -- ^ The value containing the text to search in. 39 | -> Maybe (Fuzzy t s) -- ^ The original value, rendered string and score. 40 | match extract caseSensitive pattern t = 41 | if null pat 42 | then Just (Fuzzy t totalScore) 43 | else Nothing 44 | where 45 | null :: (T.TextualMonoid s) => s -> Bool 46 | null = not . T.any (const True) 47 | 48 | s = extract t 49 | (s', pattern') = let f = T.map toLower in 50 | if caseSensitive 51 | then (s, pattern) 52 | else (f s, f pattern) 53 | 54 | (totalScore, _, pat) = 55 | T.foldl' 56 | undefined 57 | (\(tot, cur, pat') c -> 58 | case T.splitCharacterPrefix pat' of 59 | Nothing -> (tot, 0, pat') 60 | Just (x, xs) -> 61 | if x == c then 62 | let cur' = cur * 2 + 1 in 63 | (tot + cur', cur', xs) 64 | else (tot, 0, pat') 65 | ) (0, 0, pattern') s' 66 | 67 | -- | The function to filter a list of values by fuzzy search on the text extracted from them. 68 | -- 69 | -- >>> filter fst False "ML" [("Standard ML", 1990),("OCaml",1996),("Scala",2003)] 70 | -- [ Fuzzy {original = ("Standard ML",1990), score = 4} 71 | -- , Fuzzy {original = ("OCaml",1996), score = 4} ] 72 | filterBy :: (T.TextualMonoid s) 73 | => (t -> s) -- ^ The function to extract the text from the container. 74 | -> s -- ^ Pattern. 75 | -> [t] -- ^ The list of values containing the text to search in. 76 | -> [t] -- ^ The list of results, sorted, highest score first. 77 | filterBy extract pattern ts = 78 | map original $ 79 | sortOn (Down . score) 80 | (mapMaybe (match extract False pattern) ts) 81 | 82 | -- | For filtering on normal text values 83 | -- 84 | -- >>> simpleFilter "vm" ["vim", "emacs", "virtual machine"] 85 | -- ["vim","virtual machine"] 86 | simpleFilter :: (T.TextualMonoid s) 87 | => s -- ^ Pattern to look for. 88 | -> [s] -- ^ List of texts to check. 89 | -> [s] -- ^ The ones that match. 90 | simpleFilter pattern xs = 91 | filterBy id pattern xs 92 | 93 | 94 | -- | Returns false if the pattern and the text do not match at all. 95 | -- Returns true otherwise. 96 | -- 97 | -- >>> test "brd" "bread" 98 | -- True 99 | test :: (T.TextualMonoid s) 100 | => s -> s -> Bool 101 | test p s = isJust (match id False p s) 102 | -------------------------------------------------------------------------------- /src/Haskell/Ide/Engine/Types.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE RankNTypes #-} 2 | {-# LANGUAGE GADTs #-} 3 | {-# LANGUAGE DataKinds #-} 4 | {-# LANGUAGE PatternSynonyms #-} 5 | module Haskell.Ide.Engine.Types where 6 | 7 | import Haskell.Ide.Engine.MonadTypes 8 | import qualified Language.Haskell.LSP.Types as J 9 | 10 | -- --------------------------------------------------------------------- 11 | 12 | -- | A callback from a request. 13 | type RequestCallback m a = a -> m () 14 | 15 | -- | Used to track a request through the system, for logging 16 | type TrackingNumber = Int 17 | 18 | -- | Requests are parametric in the monad m 19 | -- that their callback expects to be in. 20 | pattern GReq :: TrackingNumber 21 | -> String 22 | -> Maybe Uri 23 | -> Maybe (Uri, Int) 24 | -> Maybe J.LspId 25 | -> RequestCallback m a1 26 | -> a1 27 | -> IdeGhcM (IdeResult a1) 28 | -> PluginRequest m 29 | pattern GReq a s b c d e f g = Right (GhcRequest a s b c d e f g) 30 | 31 | pattern IReq :: TrackingNumber -> String -> J.LspId -> RequestCallback m a -> IdeDeferM (IdeResult a) -> Either (IdeRequest m) b 32 | pattern IReq a s b c d = Left (IdeRequest a s b c d) 33 | 34 | type PluginRequest m = Either (IdeRequest m) (GhcRequest m) 35 | 36 | data GhcRequest m = forall a. GhcRequest 37 | { pinMsgNum :: TrackingNumber -- ^ Exists to facilitate logging/tracing 38 | , pinDesc :: String -- ^ Description of the request for debugging 39 | , pinContext :: Maybe J.Uri 40 | , pinDocVer :: Maybe (J.Uri, Int) 41 | , pinLspReqId :: Maybe J.LspId 42 | , pinCallback :: RequestCallback m a 43 | , pinDefault :: a 44 | , pinReq :: IdeGhcM (IdeResult a) 45 | } 46 | 47 | data IdeRequest m = forall a. IdeRequest 48 | { pureMsgNum :: TrackingNumber -- ^ Exists to facilitate logging/tracing 49 | , pureDesc :: String 50 | , pureReqId :: J.LspId 51 | , pureReqCallback :: RequestCallback m a 52 | , pureReq :: IdeDeferM (IdeResult a) 53 | } 54 | 55 | -- --------------------------------------------------------------------- 56 | -------------------------------------------------------------------------------- /src/Haskell/Ide/Engine/Version.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {-# LANGUAGE TemplateHaskell #-} 3 | {-# LANGUAGE OverloadedStrings #-} 4 | -- | Information and display strings for HIE's version 5 | -- and the current project's version 6 | module Haskell.Ide.Engine.Version where 7 | 8 | import Data.Maybe 9 | import Development.GitRev (gitCommitCount) 10 | import Distribution.System (buildArch) 11 | import Distribution.Text (display) 12 | import Options.Applicative.Simple (simpleVersion) 13 | import Haskell.Ide.Engine.Cradle (execProjectGhc) 14 | import qualified HIE.Bios.Types as Bios 15 | import qualified Haskell.Ide.Engine.Cradle as Bios 16 | import qualified Paths_haskell_ide_engine as Meta 17 | import System.Directory 18 | import System.Info 19 | 20 | hieVersion :: String 21 | hieVersion = 22 | let commitCount = $gitCommitCount 23 | in concat $ concat 24 | [ [$(simpleVersion Meta.version)] 25 | -- Leave out number of commits for --depth=1 clone 26 | -- See https://github.com/commercialhaskell/stack/issues/792 27 | , [" (" ++ commitCount ++ " commits)" | commitCount /= ("1"::String) && 28 | commitCount /= ("UNKNOWN" :: String)] 29 | , [" ", display buildArch] 30 | , [" ", hieGhcDisplayVersion] 31 | ] 32 | 33 | -- --------------------------------------------------------------------- 34 | 35 | hieGhcDisplayVersion :: String 36 | hieGhcDisplayVersion = compilerName ++ "-" ++ VERSION_ghc 37 | 38 | getProjectGhcVersion :: Bios.Cradle Bios.CabalHelper -> IO String 39 | getProjectGhcVersion crdl = 40 | fmap 41 | (fromMaybe "No System GHC Found.") 42 | (execProjectGhc crdl ["--numeric-version"]) 43 | 44 | 45 | hieGhcVersion :: String 46 | hieGhcVersion = VERSION_ghc 47 | 48 | -- --------------------------------------------------------------------- 49 | 50 | checkCabalInstall :: IO Bool 51 | checkCabalInstall = isJust <$> findExecutable "cabal" 52 | 53 | -- --------------------------------------------------------------------- 54 | -------------------------------------------------------------------------------- /stack-8.4.2.yaml: -------------------------------------------------------------------------------- 1 | resolver: nightly-2018-05-30 # last nightly for GHC 8.4.2 2 | packages: 3 | - . 4 | - hie-plugin-api 5 | 6 | extra-deps: 7 | # - ./submodules/HaRe 8 | 9 | - aeson-1.4.6.0 10 | - aeson-pretty-0.8.8 11 | - base-compat-0.9.3 12 | - base-orphans-0.8.2 13 | - bifunctors-5.5.6 14 | - brittany-0.12.1.1 15 | - bytestring-trie-0.2.5.0 16 | - Cabal-3.0.2.0 17 | - cabal-doctest-1.0.8 18 | - cabal-helper-1.1.0.0 19 | - cabal-plan-0.5.0.0 20 | - connection-0.3.1 # for network and network-bsd 21 | - constrained-dynamic-0.1.0.0 22 | - extra-1.6.21 23 | - file-embed-0.0.11 24 | - filepattern-0.1.1 25 | - floskell-0.10.2 26 | - generic-deriving-1.13.1 27 | - ghc-exactprint-0.6.2 # for HaRe 28 | - ghc-lib-parser-8.8.2.20200205 29 | - ghc-lib-parser-ex-8.8.5.3 30 | - ghc-paths-0.1.0.12 31 | - haddock-api-2.20.0@rev:1 32 | - haddock-library-1.6.0 33 | - happy-1.19.12 34 | - haskell-lsp-0.20.0.0 35 | - haskell-lsp-types-0.20.0.0 36 | - haskell-src-exts-1.22.0 37 | - haskell-src-exts-util-0.2.5 38 | - hie-bios-0.5.0 39 | - hlint-2.2.11 40 | - hoogle-5.0.17.15 41 | - hsimport-0.11.0@rev:2 42 | - hslogger-1.3.1.0 43 | - invariant-0.5.3 44 | - lens-4.18.1 45 | - libyaml-0.1.1.0 46 | - lsp-test-0.10.1.0 47 | - microlens-th-0.4.3.2 48 | - monad-dijkstra-0.1.1.2 49 | - network-3.1.1.1 # for hslogger 50 | - network-bsd-2.8.1.0 # for hslogger 51 | - parser-combinators-1.2.1 52 | - profunctors-5.5.1 53 | - pretty-show-1.8.2 54 | - resourcet-1.2.3 # forced by unliftio-core >= 0.2 55 | - rope-utf16-splay-0.3.1.0 56 | - simple-sendfile-0.2.30 # for network and network-bsd 57 | - socks-0.6.1 # for network and network-bsd 58 | - syz-0.2.0.0 59 | - type-equality-1 60 | - unix-compat-0.5.2 61 | - unliftio-0.2.12.1 62 | - unliftio-core-0.2.0.1 63 | - unordered-containers-0.2.10.0 64 | - yaml-0.11.2.0 65 | - th-abstraction-0.3.1.0 66 | - windns-0.1.0.0 67 | - yi-rope-0.11 68 | # To make build work in windows 7 69 | - unix-time-0.4.7 70 | - temporary-1.2.1.1 71 | - time-compat-1.9.2.2 72 | - time-manager-0.0.0 # for http2 73 | - wai-3.2.2.1 # for network and network-bsd 74 | - warp-3.2.28 # for network and network-bsd 75 | 76 | flags: 77 | haskell-ide-engine: 78 | pedantic: true 79 | hie-plugin-api: 80 | pedantic: true 81 | 82 | # allow-newer: true 83 | 84 | nix: 85 | packages: [ icu libcxx zlib ] 86 | 87 | concurrent-tests: false 88 | -------------------------------------------------------------------------------- /stack-8.4.3.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-12.14 # Last for GHC 8.4.3 2 | packages: 3 | - . 4 | - hie-plugin-api 5 | 6 | extra-deps: 7 | # - ./submodules/HaRe 8 | 9 | - QuickCheck-2.13.2 10 | - aeson-1.4.6.0 11 | - aeson-pretty-0.8.8 12 | - ansi-terminal-0.10.2 13 | - ansi-wl-pprint-0.6.9 14 | - assoc-1.0.1 15 | - async-2.2.2 16 | - base-compat-0.11.1 17 | - base-orphans-0.8.2 18 | - bifunctors-5.5.7 19 | - brittany-0.12.1.1 20 | - bytestring-trie-0.2.5.0 21 | - Cabal-3.0.2.0 22 | - cabal-doctest-1.0.8 23 | - cabal-helper-1.1.0.0 24 | - cabal-plan-0.6.2.0 25 | - connection-0.3.1 # for network and network-bsd 26 | - constrained-dynamic-0.1.0.0 27 | - dec-0.0.3 28 | - extra-1.6.21 29 | - file-embed-0.0.11.1 30 | - filepattern-0.1.1 31 | - floskell-0.10.2 32 | - generic-deriving-1.13.1 33 | - ghc-exactprint-0.6.2 # for HaRe 34 | - ghc-lib-parser-8.8.2.20200205 35 | - ghc-lib-parser-ex-8.8.5.3 36 | - ghc-paths-0.1.0.12 37 | - haddock-api-2.20.0@rev:1 38 | - haddock-library-1.6.0 39 | - haskell-lsp-0.20.0.0 40 | - haskell-lsp-types-0.20.0.0 41 | - haskell-src-exts-1.22.0 42 | - haskell-src-exts-util-0.2.5 43 | - happy-1.19.12 44 | - hie-bios-0.5.0 45 | - hlint-2.2.11 46 | - hoogle-5.0.17.15 47 | - hsimport-0.11.0@rev:2 48 | - hslogger-1.3.1.0 49 | - hspec-2.7.1 50 | - hspec-core-2.7.1 51 | - hspec-discover-2.7.1 52 | - indexed-profunctors-0.1 53 | - invariant-0.5.3 54 | - lens-4.18.1 55 | - libyaml-0.1.1.1 56 | - lsp-test-0.10.1.0 57 | - microlens-th-0.4.3.4 58 | - monad-dijkstra-0.1.1.2 59 | - network-3.1.1.1 # for hslogger 60 | - network-bsd-2.8.1.0 # for hslogger 61 | - optics-core-0.2 62 | - optparse-applicative-0.15.1.0 63 | - parser-combinators-1.2.1 64 | - profunctors-5.5.1 65 | - quickcheck-instances-0.3.22 66 | - resourcet-1.2.3 # forced by unliftio-core >= 0.2 67 | - rope-utf16-splay-0.3.1.0 68 | - semialign-1.1 69 | - semigroupoids-5.3.4 70 | - simple-sendfile-0.2.30 # for network and network-bsd 71 | - singleton-bool-0.1.5 72 | - socks-0.6.1 # for network and network-bsd 73 | - splitmix-0.0.3 74 | - tagged-0.8.6 75 | - th-abstraction-0.3.1.0 76 | - these-1.0.1 77 | - topograph-1 78 | - type-equality-1 79 | - unix-compat-0.5.2 80 | - unliftio-0.2.12.1 81 | - unliftio-core-0.2.0.1 82 | - unordered-containers-0.2.10.0 83 | - vector-0.12.1.2 84 | - yaml-0.11.2.0 85 | # To make build work in windows 7 86 | - unix-time-0.4.7 87 | - temporary-1.2.1.1 88 | - time-compat-1.9.2.2 89 | - time-manager-0.0.0 # for http2 90 | - warp-3.2.28 # for network and network-bsd 91 | - wai-3.2.2.1 # for network and network-bsd 92 | 93 | 94 | flags: 95 | haskell-ide-engine: 96 | pedantic: true 97 | hie-plugin-api: 98 | pedantic: true 99 | 100 | # allow-newer: true 101 | 102 | nix: 103 | packages: [icu libcxx zlib] 104 | 105 | concurrent-tests: false 106 | -------------------------------------------------------------------------------- /stack-8.4.4.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-12.26 # LTS 12.15 is first to support GHC 8.4.4 2 | packages: 3 | - . 4 | - hie-plugin-api 5 | 6 | extra-deps: 7 | # - ./submodules/HaRe 8 | 9 | - aeson-1.4.6.0 10 | - aeson-pretty-0.8.8 11 | - base-orphans-0.8.2 12 | - bifunctors-5.5.6 13 | - brittany-0.12.1.1 14 | - bytestring-trie-0.2.5.0 15 | - Cabal-3.0.2.0 16 | - cabal-doctest-1.0.8 17 | - cabal-helper-1.1.0.0 18 | - cabal-plan-0.5.0.0 19 | - connection-0.3.1 # for network and network-bsd 20 | - constrained-dynamic-0.1.0.0 21 | - extra-1.6.21 22 | - file-embed-0.0.11 23 | - filepattern-0.1.1 24 | - floskell-0.10.2 25 | - generic-deriving-1.13.1 26 | - ghc-exactprint-0.6.2 # for HaRe 27 | - ghc-lib-parser-8.8.2.20200205 28 | - ghc-lib-parser-ex-8.8.5.3 29 | - ghc-paths-0.1.0.12 30 | - haddock-api-2.20.0@rev:1 31 | - haddock-library-1.6.0 32 | - happy-1.19.12 33 | - haskell-lsp-0.20.0.0 34 | - haskell-lsp-types-0.20.0.0 35 | - haskell-src-exts-1.22.0 36 | - haskell-src-exts-util-0.2.5 37 | - hie-bios-0.5.0 38 | - hlint-2.2.11 39 | - hoogle-5.0.17.15 40 | - hsimport-0.11.0@rev:2 41 | - hslogger-1.3.1.0 42 | - invariant-0.5.3 43 | - lens-4.18.1 44 | - libyaml-0.1.1.0 45 | - lsp-test-0.10.1.0 46 | - microlens-th-0.4.3.2 47 | - monad-dijkstra-0.1.1.2 48 | - network-3.1.1.1 # for hslogger 49 | - network-bsd-2.8.1.0 # for hslogger 50 | - optparse-simple-0.1.0 51 | - parser-combinators-1.2.1 52 | - pretty-show-1.9.5 53 | - profunctors-5.5.1 54 | - resourcet-1.2.3 # forced by unliftio-core >= 0.2 55 | - rope-utf16-splay-0.3.1.0 56 | - simple-sendfile-0.2.30 # for network and network-bsd 57 | - socks-0.6.1 # for network and network-bsd 58 | - syz-0.2.0.0 59 | - unix-compat-0.5.2 60 | - unliftio-0.2.12.1 61 | - unliftio-core-0.2.0.1 62 | - unordered-containers-0.2.10.0 63 | - yaml-0.11.2.0 64 | - th-abstraction-0.3.1.0 65 | - type-equality-1 66 | # To make build work in windows 7 67 | - unix-time-0.4.7 68 | - temporary-1.2.1.1 69 | - time-compat-1.9.2.2 70 | - time-manager-0.0.0 # for http2 71 | - warp-3.2.28 # for network and network-bsd 72 | - wai-3.2.2.1 # for network and network-bsd 73 | 74 | flags: 75 | haskell-ide-engine: 76 | pedantic: true 77 | hie-plugin-api: 78 | pedantic: true 79 | 80 | # allow-newer: true 81 | 82 | nix: 83 | packages: [icu libcxx zlib] 84 | 85 | concurrent-tests: false 86 | -------------------------------------------------------------------------------- /stack-8.6.4.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-13.19 # GHC 8.6.4 2 | packages: 3 | - . 4 | - hie-plugin-api 5 | 6 | extra-deps: 7 | # - ./submodules/HaRe 8 | 9 | - aeson-1.4.6.0 10 | - aeson-pretty-0.8.8 11 | - brittany-0.12.1.1 12 | - butcher-1.3.2.1 13 | - bytestring-trie-0.2.5.0 14 | - Cabal-3.0.2.0 15 | - cabal-doctest-1.0.8 16 | - cabal-helper-1.1.0.0 17 | - cabal-plan-0.5.0.0 18 | - constrained-dynamic-0.1.0.0 19 | - extra-1.6.21 20 | - floskell-0.10.2 21 | - ghc-exactprint-0.6.2 # for HaRe 22 | - ghc-lib-parser-8.8.2.20200205 23 | - ghc-lib-parser-ex-8.8.5.3 24 | - ghc-paths-0.1.0.12 25 | - haddock-api-2.22.0@rev:1 26 | - happy-1.19.12 27 | - haskell-lsp-0.20.0.0 28 | - haskell-lsp-types-0.20.0.0 29 | - haskell-src-exts-1.22.0 30 | - hie-bios-0.5.0 31 | - hlint-2.2.11 32 | - hoogle-5.0.17.15 33 | - hsimport-0.11.0@rev:2 34 | - lens-4.18 35 | - lsp-test-0.10.1.0 36 | - microlens-th-0.4.2.3@rev:1 37 | - monad-dijkstra-0.1.1.2@rev:1 38 | - monad-memo-0.4.1 39 | - multistate-0.8.0.1 40 | - ormolu-0.0.3.1 41 | - parser-combinators-1.2.1 42 | - resourcet-1.2.3 # forced by unliftio-core >= 0.2 43 | - rope-utf16-splay-0.3.1.0 44 | - syz-0.2.0.0 45 | - temporary-1.2.1.1 46 | - th-abstraction-0.3.1.0 47 | - time-compat-1.9.2.2 48 | - type-equality-1 49 | - unix-compat-0.5.2 50 | - unliftio-0.2.12.1 51 | - unliftio-core-0.2.0.1 52 | - unordered-containers-0.2.10.0 53 | - yaml-0.11.2.0 54 | # To make build work in windows 7 55 | - unix-time-0.4.7 56 | 57 | flags: 58 | haskell-ide-engine: 59 | pedantic: true 60 | hie-plugin-api: 61 | pedantic: true 62 | 63 | # allow-newer: true 64 | 65 | nix: 66 | packages: [icu libcxx zlib] 67 | 68 | concurrent-tests: false 69 | -------------------------------------------------------------------------------- /stack-8.6.5.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-14.22 2 | packages: 3 | - . 4 | - hie-plugin-api 5 | 6 | extra-deps: 7 | # - ./submodules/HaRe 8 | 9 | - aeson-1.4.6.0 10 | - aeson-pretty-0.8.8 11 | - ansi-terminal-0.10.2 12 | - ansi-wl-pprint-0.6.9 13 | - base-compat-0.11.1 14 | - brittany-0.12.1.1 15 | - bytestring-trie-0.2.5.0 16 | - Cabal-3.0.2.0 17 | - cabal-helper-1.1.0.0 18 | - cabal-plan-0.6.2.0 19 | - clock-0.7.2 20 | - constrained-dynamic-0.1.0.0 21 | - extra-1.6.21 22 | - floskell-0.10.2 23 | - ghc-exactprint-0.6.2 # for HaRe 24 | - ghc-lib-parser-8.8.2.20200205 25 | - ghc-lib-parser-ex-8.8.5.3 26 | - haddock-api-2.22.0@rev:1 27 | - haskell-lsp-0.20.0.0 28 | - haskell-lsp-types-0.20.0.0 29 | - haskell-src-exts-1.22.0 30 | - hie-bios-0.5.0 31 | - hlint-2.2.11 32 | - hoogle-5.0.17.15 33 | - hsimport-0.11.0@rev:2 34 | - indexed-profunctors-0.1 35 | - lens-4.18 36 | - lsp-test-0.10.1.0 37 | - monad-dijkstra-0.1.1.2 38 | - optics-core-0.2 39 | - optparse-applicative-0.15.1.0 40 | - ormolu-0.0.3.1 41 | - parser-combinators-1.2.1 42 | - resourcet-1.2.3 # forced by unliftio-core >= 0.2 43 | - semialign-1.1 44 | - temporary-1.2.1.1 45 | - topograph-1 46 | - type-equality-1 47 | - unliftio-0.2.12.1 48 | - unliftio-core-0.2.0.1 49 | 50 | flags: 51 | haskell-ide-engine: 52 | pedantic: true 53 | hie-plugin-api: 54 | pedantic: true 55 | 56 | # allow-newer: true 57 | 58 | nix: 59 | packages: [ icu libcxx zlib ] 60 | 61 | concurrent-tests: false 62 | -------------------------------------------------------------------------------- /stack-8.8.2.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-15.3 # Last 8.8.2 2 | packages: 3 | - . 4 | - hie-plugin-api 5 | 6 | extra-deps: 7 | # - ./submodules/HaRe 8 | 9 | - apply-refact-0.7.0.0 10 | - brittany-0.12.1.1 11 | - bytestring-trie-0.2.5.0 12 | - Cabal-3.0.2.0 13 | - cabal-helper-1.1.0.0 14 | - clock-0.7.2 15 | - constrained-dynamic-0.1.0.0 16 | - floskell-0.10.2 17 | - ghc-lib-parser-8.8.2.20200205 18 | - ghc-lib-parser-ex-8.8.5.3 19 | - haddock-api-2.23.1 20 | - haddock-library-1.8.0 21 | - haskell-lsp-0.20.0.0 22 | - haskell-lsp-types-0.20.0.0 23 | - lsp-test-0.10.1.0 24 | - hie-bios-0.5.0 25 | - hlint-2.2.11 26 | - hoogle-5.0.17.15 27 | - hsimport-0.11.0@rev:2 28 | - ilist-0.3.1.0 29 | - monad-dijkstra-0.1.1.2 30 | - ormolu-0.0.3.1 31 | - resourcet-1.2.3 # forced by unliftio-core >= 0.2 32 | - semigroups-0.18.5 33 | - temporary-1.2.1.1 34 | - unliftio-0.2.12.1 35 | - unliftio-core-0.2.0.1 36 | 37 | flags: 38 | haskell-ide-engine: 39 | pedantic: true 40 | hie-plugin-api: 41 | pedantic: true 42 | 43 | # allow-newer: true 44 | 45 | nix: 46 | packages: [ icu libcxx zlib ] 47 | 48 | concurrent-tests: false 49 | -------------------------------------------------------------------------------- /stack-8.8.3.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-15.10 2 | packages: 3 | - . 4 | - hie-plugin-api 5 | 6 | extra-deps: 7 | # - ./submodules/HaRe 8 | 9 | - apply-refact-0.7.0.0 10 | - bytestring-trie-0.2.5.0@rev:1 11 | - Cabal-3.0.2.0 12 | - cabal-helper-1.1.0.0 13 | - clock-0.7.2 14 | - constrained-dynamic-0.1.0.0 15 | - floskell-0.10.2 16 | - ghc-lib-parser-8.8.2.20200205 17 | - ghc-lib-parser-ex-8.8.5.3 18 | - haddock-api-2.23.1 19 | - hoogle-5.0.17.15 20 | - hsimport-0.11.0 21 | - ilist-0.3.1.0 22 | - monad-dijkstra-0.1.1.2 23 | - semigroups-0.18.5 24 | - temporary-1.2.1.1 25 | - unliftio-core-0.2.0.1 26 | - hie-bios-0.5.0 27 | 28 | flags: 29 | haskell-ide-engine: 30 | pedantic: true 31 | hie-plugin-api: 32 | pedantic: true 33 | 34 | nix: 35 | packages: [ icu libcxx zlib ] 36 | 37 | concurrent-tests: false 38 | -------------------------------------------------------------------------------- /stack.yaml: -------------------------------------------------------------------------------- 1 | resolver: nightly-2020-05-01 2 | 3 | packages: 4 | - . 5 | - hie-plugin-api 6 | 7 | extra-deps: 8 | # - ./submodules/HaRe 9 | 10 | - apply-refact-0.7.0.0 11 | - bytestring-trie-0.2.5.0 12 | - cabal-helper-1.1.0.0 13 | - clock-0.7.2 14 | - constrained-dynamic-0.1.0.0 15 | - floskell-0.10.2 16 | - ghc-lib-parser-8.8.3.20200412.1 17 | - ghc-lib-parser-ex-8.8.5.3 18 | - haddock-api-2.23.1 19 | - haddock-library-1.8.0 20 | - haskell-lsp-0.20.0.0 21 | - haskell-lsp-types-0.20.0.0 22 | - haskell-src-exts-1.22.0 23 | - hoogle-5.0.17.15 24 | - hie-bios-0.5.0 25 | - hsimport-0.11.0 26 | - ilist-0.3.1.0 27 | - lsp-test-0.10.1.0 28 | - monad-dijkstra-0.1.1.2 29 | - ormolu-0.0.3.1 30 | - semigroups-0.18.5 31 | - temporary-1.2.1.1 32 | - unliftio-core-0.2.0.1 33 | 34 | flags: 35 | haskell-ide-engine: 36 | pedantic: true 37 | hie-plugin-api: 38 | pedantic: true 39 | 40 | nix: 41 | packages: [ icu libcxx zlib ] 42 | 43 | concurrent-tests: false 44 | -------------------------------------------------------------------------------- /test/functional/CommandSpec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module CommandSpec where 3 | 4 | import Control.Lens hiding (List) 5 | import Control.Monad.IO.Class 6 | import qualified Data.Text as T 7 | import Data.Char 8 | import Language.Haskell.LSP.Test 9 | import Language.Haskell.LSP.Types as LSP 10 | import Language.Haskell.LSP.Types.Lens as LSP 11 | import Test.Hspec 12 | import TestUtils 13 | 14 | spec :: Spec 15 | spec = describe "commands" $ do 16 | it "are prefixed" $ runSession hieCommand fullCaps "test/testdata/" $ do 17 | ResponseMessage _ _ (Just res) Nothing <- initializeResponse 18 | let List cmds = res ^. LSP.capabilities . executeCommandProvider . _Just . commands 19 | f x = (T.length (T.takeWhile isNumber x) >= 1) && (T.count ":" x >= 2) 20 | liftIO $ do 21 | cmds `shouldSatisfy` all f 22 | cmds `shouldNotSatisfy` null 23 | 24 | it "get de-prefixed" $ runSession hieCommand fullCaps "test/testdata/" $ do 25 | ResponseMessage _ _ _ (Just err) <- request 26 | WorkspaceExecuteCommand 27 | (ExecuteCommandParams "1234:package:add" (Just (List [])) Nothing) :: Session ExecuteCommandResponse 28 | let ResponseError _ msg _ = err 29 | -- We expect an error message about the dud arguments, but should pickup "add" and "package" 30 | liftIO $ msg `shouldSatisfy` T.isInfixOf "while parsing args for add in plugin package" 31 | -------------------------------------------------------------------------------- /test/functional/DefinitionSpec.hs: -------------------------------------------------------------------------------- 1 | module DefinitionSpec where 2 | 3 | -- import Control.Applicative.Combinators 4 | import Control.Lens 5 | import Control.Monad.IO.Class 6 | import Language.Haskell.LSP.Test 7 | import Language.Haskell.LSP.Types 8 | import Language.Haskell.LSP.Types.Lens 9 | import System.Directory 10 | import Test.Hspec 11 | import TestUtils 12 | 13 | spec :: Spec 14 | spec = describe "definitions" $ do 15 | it "goto's symbols" $ runSession hieCommand fullCaps "test/testdata" $ do 16 | doc <- openDoc "References.hs" "haskell" 17 | defs <- getDefinitions doc (Position 7 8) 18 | let expRange = Range (Position 4 0) (Position 4 3) 19 | liftIO $ defs `shouldBe` [Location (doc ^. uri) expRange] 20 | 21 | -- ----------------------------------- 22 | 23 | it "goto's imported modules" $ runSession hieCommand fullCaps "test/testdata/definition" $ do 24 | doc <- openDoc "Foo.hs" "haskell" 25 | defs <- getDefinitions doc (Position 2 8) 26 | liftIO $ do 27 | fp <- canonicalizePath "test/testdata/definition/Bar.hs" 28 | defs `shouldBe` [Location (filePathToUri fp) zeroRange] 29 | 30 | -- ----------------------------------- 31 | 32 | it "goto's exported modules" $ runSession hieCommand fullCaps "test/testdata/definition" $ do 33 | doc <- openDoc "Foo.hs" "haskell" 34 | defs <- getDefinitions doc (Position 0 15) 35 | liftIO $ do 36 | fp <- canonicalizePath "test/testdata/definition/Bar.hs" 37 | defs `shouldBe` [Location (filePathToUri fp) zeroRange] 38 | 39 | -- ----------------------------------- 40 | 41 | it "goto's imported modules that are loaded" $ runSession hieCommand fullCaps "test/testdata/definition" $ do 42 | doc <- openDoc "Foo.hs" "haskell" 43 | _ <- openDoc "Bar.hs" "haskell" 44 | defs <- getDefinitions doc (Position 2 8) 45 | liftIO $ do 46 | fp <- canonicalizePath "test/testdata/definition/Bar.hs" 47 | defs `shouldBe` [Location (filePathToUri fp) zeroRange] 48 | 49 | -- ----------------------------------- 50 | 51 | it "goto's imported modules that are loaded, and then closed" $ 52 | runSession hieCommand fullCaps "test/testdata/definition" $ do 53 | doc <- openDoc "Foo.hs" "haskell" 54 | otherDoc <- openDoc "Bar.hs" "haskell" 55 | closeDoc otherDoc 56 | defs <- getDefinitions doc (Position 2 8) 57 | _ <- waitForDiagnostics 58 | liftIO $ putStrLn "D" 59 | liftIO $ do 60 | fp <- canonicalizePath "test/testdata/definition/Bar.hs" 61 | defs `shouldBe` [Location (filePathToUri fp) zeroRange] 62 | liftIO $ putStrLn "E" -- AZ 63 | 64 | noDiagnostics 65 | 66 | 67 | zeroRange :: Range 68 | zeroRange = Range (Position 0 0) (Position 0 0) 69 | -------------------------------------------------------------------------------- /test/functional/DiagnosticsSpec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module DiagnosticsSpec where 4 | 5 | import Control.Applicative.Combinators 6 | import Control.Lens hiding (List) 7 | import Control.Monad.IO.Class 8 | import Data.Aeson (toJSON) 9 | import qualified Data.Text as T 10 | import qualified Data.Default 11 | import Haskell.Ide.Engine.MonadFunctions 12 | import Haskell.Ide.Engine.Config 13 | import Language.Haskell.LSP.Test hiding (message) 14 | import Language.Haskell.LSP.Types 15 | import qualified Language.Haskell.LSP.Types.Lens as LSP 16 | import Test.Hspec 17 | import TestUtils 18 | import Utils 19 | 20 | -- --------------------------------------------------------------------- 21 | 22 | spec :: Spec 23 | spec = describe "diagnostics providers" $ do 24 | describe "diagnostics triggers" $ 25 | it "runs diagnostics on save" $ 26 | runSession hieCommandExamplePlugin codeActionSupportCaps "test/testdata" $ do 27 | logm "starting DiagnosticSpec.runs diagnostic on save" 28 | doc <- openDoc "ApplyRefact2.hs" "haskell" 29 | 30 | diags@(reduceDiag:_) <- waitForDiagnostics 31 | 32 | liftIO $ do 33 | length diags `shouldBe` 2 34 | reduceDiag ^. LSP.range `shouldBe` Range (Position 1 0) (Position 1 12) 35 | reduceDiag ^. LSP.severity `shouldBe` Just DsInfo 36 | reduceDiag ^. LSP.code `shouldBe` Just (StringValue "Eta reduce") 37 | reduceDiag ^. LSP.source `shouldBe` Just "hlint" 38 | 39 | diags2a <- waitForDiagnostics 40 | 41 | liftIO $ length diags2a `shouldBe` 2 42 | 43 | sendNotification TextDocumentDidSave (DidSaveTextDocumentParams doc) 44 | 45 | diags3@(d:_) <- waitForDiagnosticsSource "eg2" 46 | 47 | liftIO $ do 48 | length diags3 `shouldBe` 1 49 | d ^. LSP.range `shouldBe` Range (Position 0 0) (Position 1 0) 50 | d ^. LSP.severity `shouldBe` Nothing 51 | d ^. LSP.code `shouldBe` Nothing 52 | d ^. LSP.message `shouldBe` T.pack "Example plugin diagnostic, triggered byDiagnosticOnSave" 53 | 54 | describe "typed hole errors" $ 55 | it "is deferred" $ 56 | runSession hieCommand fullCaps "test/testdata" $ do 57 | _ <- openDoc "TypedHoles.hs" "haskell" 58 | [diag] <- waitForDiagnosticsSource "bios" 59 | liftIO $ diag ^. LSP.severity `shouldBe` Just DsWarning 60 | 61 | describe "Warnings are warnings" $ 62 | it "Overrides -Werror" $ 63 | runSession hieCommand fullCaps "test/testdata/wErrorTest" $ do 64 | _ <- openDoc "src/WError.hs" "haskell" 65 | [diag] <- waitForDiagnosticsSource "bios" 66 | liftIO $ diag ^. LSP.severity `shouldBe` Just DsWarning 67 | 68 | describe "only diagnostics on save" $ 69 | it "Respects diagnosticsOnChange setting" $ 70 | runSession hieCommandExamplePlugin codeActionSupportCaps "test/testdata" $ do 71 | let config = Data.Default.def { diagnosticsOnChange = False } :: Config 72 | sendNotification WorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config)) 73 | doc <- openDoc "Hover.hs" "haskell" 74 | diags <- waitForDiagnostics 75 | 76 | liftIO $ do 77 | length diags `shouldBe` 0 78 | 79 | let te = TextEdit (Range (Position 0 0) (Position 0 13)) "" 80 | _ <- applyEdit doc te 81 | skipManyTill loggingNotification noDiagnostics 82 | 83 | sendNotification TextDocumentDidSave (DidSaveTextDocumentParams doc) 84 | diags2 <- waitForDiagnostics 85 | liftIO $ 86 | length diags2 `shouldBe` 1 87 | 88 | -- --------------------------------------------------------------------- 89 | -------------------------------------------------------------------------------- /test/functional/FunctionalBadProjectSpec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module FunctionalBadProjectSpec where 4 | 5 | -- import Control.Lens hiding (List) 6 | -- import Control.Monad.IO.Class 7 | -- import qualified Data.Text as T 8 | -- import Language.Haskell.LSP.Test hiding (message) 9 | -- import Language.Haskell.LSP.Types as LSP 10 | -- import Language.Haskell.LSP.Types.Lens as LSP hiding (contents, error ) 11 | import Test.Hspec 12 | -- import TestUtils 13 | -- import Utils 14 | 15 | -- --------------------------------------------------------------------- 16 | -- TODO: Currently this can not succeed, since such an error is thrown in "runActionWithContext" which 17 | -- can produce diagnostics at the moment. Needs more investigation 18 | -- TODO: @fendor: Add issue link here 19 | -- 20 | spec :: Spec 21 | spec = describe "behaviour on malformed projects" $ 22 | it "no test executed" $ True `shouldBe` True 23 | -- it "deals with cabal file with unsatisfiable dependency" $ 24 | -- runSession hieCommandExamplePlugin codeActionSupportCaps "test/testdata/badProjects/cabal" $ do 25 | -- -- runSessionWithConfig logConfig hieCommandExamplePlugin codeActionSupportCaps "test/testdata" $ do 26 | -- _doc <- openDoc "Foo.hs" "haskell" 27 | 28 | -- diags@(d:_) <- waitForDiagnosticsSource "bios" 29 | -- -- liftIO $ show diags `shouldBe` "" 30 | -- -- liftIO $ putStrLn $ show diags 31 | -- -- liftIO $ putStrLn "a" 32 | -- liftIO $ do 33 | -- length diags `shouldBe` 1 34 | -- d ^. range `shouldBe` Range (Position 0 0) (Position 1 0) 35 | -- d ^. severity `shouldBe` (Just DsError) 36 | -- d ^. code `shouldBe` Nothing 37 | -- d ^. source `shouldBe` Just "bios" 38 | -- d ^. message `shouldBe` 39 | -- (T.pack "readCreateProcess: stack \"build\" \"--only-configure\" \".\" (exit 1): failed\n") 40 | 41 | -- --------------------------------- 42 | 43 | -- --------------------------------------------------------------------- 44 | -------------------------------------------------------------------------------- /test/functional/FunctionalSpec.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -F -pgmF hspec-discover -optF --module-name=FunctionalSpec #-} 2 | -------------------------------------------------------------------------------- /test/functional/HieBiosSpec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module HieBiosSpec where 3 | 4 | import Control.Applicative.Combinators 5 | import qualified Data.Text as T 6 | import Language.Haskell.LSP.Test 7 | import Language.Haskell.LSP.Types 8 | import Language.Haskell.LSP.Messages 9 | import System.FilePath (()) 10 | import Test.Hspec 11 | import TestUtils 12 | 13 | spec :: Spec 14 | -- Create an empty hie.yaml to trigger the parse error 15 | spec = beforeAll_ (writeFile (hieBiosErrorPath "hie.yaml") "") $ do 16 | 17 | describe "hie-bios" $ do 18 | 19 | it "loads modules inside main-is" $ runSession hieCommand fullCaps "test/testdata/hieBiosMainIs" $ do 20 | _ <- openDoc "Main.hs" "haskell" 21 | _ <- count 2 waitForDiagnostics 22 | return () 23 | 24 | it "reports errors in hie.yaml" $ runSession hieCommand fullCaps hieBiosErrorPath $ do 25 | _ <- openDoc "Foo.hs" "haskell" 26 | _ <- skipManyTill loggingNotification (satisfy isMessage) 27 | return () 28 | 29 | where hieBiosErrorPath = "test/testdata/hieBiosError" 30 | 31 | isMessage (NotShowMessage (NotificationMessage _ _ (ShowMessageParams MtError s))) = 32 | "Couldn't parse hie.yaml" `T.isInfixOf` s 33 | isMessage _ = False 34 | -------------------------------------------------------------------------------- /test/functional/HighlightSpec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module HighlightSpec where 3 | 4 | import Control.Applicative.Combinators 5 | import Control.Monad.IO.Class 6 | import Language.Haskell.LSP.Test 7 | import Language.Haskell.LSP.Types 8 | import Test.Hspec 9 | import TestUtils 10 | 11 | spec :: Spec 12 | spec = describe "highlight" $ 13 | it "works" $ runSession hieCommand fullCaps "test/testdata" $ do 14 | doc <- openDoc "Highlight.hs" "haskell" 15 | _ <- count 2 $ skipManyTill loggingNotification noDiagnostics 16 | highlights <- getHighlights doc (Position 2 2) 17 | liftIO $ do 18 | let hls = 19 | [ DocumentHighlight (mkRange 2 0 2 3) (Just HkWrite) 20 | , DocumentHighlight (mkRange 4 22 4 25) (Just HkRead) 21 | , DocumentHighlight (mkRange 3 6 3 9) (Just HkRead) 22 | , DocumentHighlight (mkRange 1 0 1 3) (Just HkRead)] 23 | mapM_ (\x -> highlights `shouldContain` [x]) hls 24 | where mkRange sl sc el ec = Range (Position sl sc) (Position el ec) 25 | -------------------------------------------------------------------------------- /test/functional/HoverSpec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module HoverSpec where 3 | 4 | import Control.Applicative.Combinators 5 | import Control.Lens 6 | import Control.Monad.IO.Class 7 | import qualified Data.Text as T 8 | import Language.Haskell.LSP.Test 9 | import Language.Haskell.LSP.Types 10 | import Language.Haskell.LSP.Types.Lens 11 | import Test.Hspec 12 | import TestUtils 13 | 14 | spec :: Spec 15 | spec = describe "hover" $ 16 | it "works" $ runSession hieCommand fullCaps "test/testdata" $ do 17 | doc <- openDoc "Hover.hs" "haskell" 18 | _ <- count 2 $ skipManyTill loggingNotification noDiagnostics 19 | Just h <- getHover doc (Position 1 19) 20 | liftIO $ do 21 | h ^. range `shouldBe` Just (Range (Position 1 16) (Position 1 19)) 22 | let 23 | hasType (HoverContents (MarkupContent MkMarkdown s)) 24 | = "\n```haskell\nsum :: [Int] -> Int\n```" `T.isPrefixOf`s 25 | hasType _ = False 26 | 27 | sumDoc = "The `sum` function computes the sum of the numbers of a structure." 28 | 29 | hasDoc (HoverContents (MarkupContent MkMarkdown s)) 30 | = sumDoc `T.isInfixOf` s 31 | hasDoc _ = False 32 | 33 | h ^. contents `shouldSatisfy` hasType 34 | h ^. contents `shouldSatisfy` hasDoc 35 | -------------------------------------------------------------------------------- /test/functional/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Control.Monad.IO.Class 4 | import Language.Haskell.LSP.Test 5 | import qualified FunctionalSpec 6 | import Test.Hspec.Runner (hspecWith) 7 | import TestUtils 8 | 9 | main :: IO () 10 | main = do 11 | setupBuildToolFiles 12 | -- run a test session to warm up the cache to prevent timeouts in other tests 13 | putStrLn "Warming up HIE cache..." 14 | runSessionWithConfig (defaultConfig { messageTimeout = 120 }) hieCommand fullCaps "test/testdata" $ 15 | liftIO $ putStrLn "HIE cache is warmed up" 16 | 17 | config <- getHspecFormattedConfig "functional" 18 | withFileLogging logFilePath $ hspecWith config $ FunctionalSpec.spec 19 | -------------------------------------------------------------------------------- /test/functional/ReferencesSpec.hs: -------------------------------------------------------------------------------- 1 | module ReferencesSpec where 2 | 3 | import Control.Lens 4 | import Control.Monad.IO.Class 5 | import Language.Haskell.LSP.Test 6 | import Language.Haskell.LSP.Types 7 | import Language.Haskell.LSP.Types.Lens 8 | import Test.Hspec 9 | import TestUtils 10 | 11 | spec :: Spec 12 | spec = describe "references" $ 13 | it "works with definitions" $ runSession hieCommand fullCaps "test/testdata" $ do 14 | doc <- openDoc "References.hs" "haskell" 15 | let pos = Position 2 7 -- foo = bar <-- 16 | refs <- getReferences doc pos True 17 | liftIO $ refs `shouldContain` map (Location (doc ^. uri)) [ 18 | mkRange 4 0 4 3 19 | , mkRange 8 11 8 14 20 | , mkRange 7 7 7 10 21 | , mkRange 4 14 4 17 22 | , mkRange 4 0 4 3 23 | , mkRange 2 6 2 9 24 | ] 25 | -- TODO: Respect withDeclaration parameter 26 | -- it "works without definitions" $ runSession hieCommand fullCaps "test/testdata" $ do 27 | -- doc <- openDoc "References.hs" "haskell" 28 | -- let pos = Position 2 7 -- foo = bar <-- 29 | -- refs <- getReferences doc pos False 30 | -- liftIO $ refs `shouldNotContain` [Location (doc ^. uri) (mkRange 4 0 4 3)] 31 | 32 | where mkRange sl sc el ec = Range (Position sl sc) (Position el ec) 33 | -------------------------------------------------------------------------------- /test/functional/RenameSpec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module RenameSpec where 3 | 4 | -- import Control.Monad.IO.Class 5 | -- import Language.Haskell.LSP.Test 6 | -- import Language.Haskell.LSP.Types 7 | import Test.Hspec 8 | -- import TestUtils 9 | 10 | spec :: Spec 11 | spec = describe "rename" $ 12 | it "works" $ pendingWith "removed because of HaRe" 13 | -- runSession hieCommand fullCaps "test/testdata" $ do 14 | -- doc <- openDoc "Rename.hs" "haskell" 15 | -- rename doc (Position 3 1) "baz" -- foo :: Int -> Int 16 | -- documentContents doc >>= liftIO . flip shouldBe expected 17 | -- where 18 | -- expected = 19 | -- "main = do\n\ 20 | -- \ x <- return $ baz 42\n\ 21 | -- \ return (baz x)\n\ 22 | -- \baz :: Int -> Int\n\ 23 | -- \baz x = x + 1\n\ 24 | -- \bar = (+ 1) . baz\n" 25 | -------------------------------------------------------------------------------- /test/functional/Utils.hs: -------------------------------------------------------------------------------- 1 | module Utils where 2 | 3 | import Data.Default 4 | import qualified Language.Haskell.LSP.Test as Test 5 | import Language.Haskell.LSP.Test hiding (message) 6 | import qualified Language.Haskell.LSP.Types.Capabilities as C 7 | 8 | -- --------------------------------------------------------------------- 9 | 10 | noLogConfig :: SessionConfig 11 | noLogConfig = Test.defaultConfig { logMessages = False } 12 | 13 | logConfig :: SessionConfig 14 | logConfig = Test.defaultConfig { logMessages = True } 15 | 16 | codeActionSupportCaps :: C.ClientCapabilities 17 | codeActionSupportCaps = def { C._textDocument = Just textDocumentCaps } 18 | where 19 | textDocumentCaps = def { C._codeAction = Just codeActionCaps } 20 | codeActionCaps = C.CodeActionClientCapabilities (Just True) (Just literalSupport) 21 | literalSupport = C.CodeActionLiteralSupport def 22 | -------------------------------------------------------------------------------- /test/plugin-dispatcher/Main.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | {-# LANGUAGE DuplicateRecordFields #-} 3 | module Main where 4 | 5 | import Control.Concurrent 6 | import Control.Concurrent.STM.TChan 7 | import Control.Monad.STM 8 | import qualified Data.Text as T 9 | import qualified Haskell.Ide.Engine.Cradle as Bios 10 | import Haskell.Ide.Engine.MonadTypes 11 | import Haskell.Ide.Engine.Scheduler 12 | import Haskell.Ide.Engine.Types 13 | import Language.Haskell.LSP.Types 14 | import TestUtils 15 | import Test.Hspec 16 | import Test.Hspec.Runner 17 | import System.Directory (getCurrentDirectory) 18 | import System.FilePath 19 | 20 | -- --------------------------------------------------------------------- 21 | 22 | main :: IO () 23 | main = do 24 | setupBuildToolFiles 25 | config <- getHspecFormattedConfig "plugin-dispatcher" 26 | withFileLogging "plugin-dispatcher.log" $ hspecWith config newPluginSpec 27 | 28 | -- --------------------------------------------------------------------- 29 | 30 | newPluginSpec :: Spec 31 | newPluginSpec = do 32 | describe "New plugin dispatcher operation" $ 33 | it "dispatches response correctly" $ do 34 | outChan <- atomically newTChan 35 | scheduler <- newScheduler (pluginDescToIdePlugins []) testOptions 36 | let defCallback = atomically . writeTChan outChan 37 | delayedCallback = \r -> threadDelay 10000 >> defCallback r 38 | 39 | let req0 = GReq 0 "0" Nothing Nothing (Just $ IdInt 0) (\_ -> return () :: IO ()) "none" $ return $ IdeResultOk $ T.pack "text0" 40 | req1 = GReq 1 "1" Nothing Nothing (Just $ IdInt 1) defCallback "none" $ return $ IdeResultOk $ T.pack "text1" 41 | req2 = GReq 2 "2" Nothing Nothing (Just $ IdInt 2) delayedCallback "none" $ return $ IdeResultOk $ T.pack "text2" 42 | req3 = GReq 3 "3" Nothing (Just (filePathToUri "test", 2)) Nothing defCallback "none" $ return $ IdeResultOk $ T.pack "text3" 43 | req4 = GReq 4 "4" Nothing Nothing (Just $ IdInt 3) defCallback "none" $ return $ IdeResultOk $ T.pack "text4" 44 | 45 | let makeReq = sendRequest scheduler 46 | 47 | cwd <- getCurrentDirectory 48 | crdl <- Bios.findLocalCradle (cwd "test" "testdata" "File.hs") 49 | 50 | pid <- forkIO $ runScheduler scheduler 51 | (\_ _ _ -> return ()) 52 | (\f x -> f x) 53 | dummyLspFuncs 54 | (\_ _ _ -> return ()) 55 | (Just crdl) 56 | 57 | updateDocument scheduler (filePathToUri "test") 3 58 | sendRequest scheduler req0 59 | makeReq req1 60 | makeReq req2 61 | cancelRequest scheduler (IdInt 2) 62 | makeReq req3 63 | makeReq req4 64 | resp1 <- atomically $ readTChan outChan 65 | resp2 <- atomically $ readTChan outChan 66 | killThread pid 67 | resp1 `shouldBe` "text1" 68 | resp2 `shouldBe` "text4" 69 | 70 | 71 | -------------------------------------------------------------------------------- /test/testdata/.hlint.yaml: -------------------------------------------------------------------------------- 1 | - ignore: {name: Redundant bracket} 2 | -------------------------------------------------------------------------------- /test/testdata/ApplyRefact.hs: -------------------------------------------------------------------------------- 1 | 2 | main = (putStrLn "hello") 3 | 4 | foo x = (x + 1) 5 | -------------------------------------------------------------------------------- /test/testdata/ApplyRefact2.hs: -------------------------------------------------------------------------------- 1 | main = undefined 2 | foo x = id x 3 | -------------------------------------------------------------------------------- /test/testdata/ApplyRefactError.hs: -------------------------------------------------------------------------------- 1 | foo :: forall a. (a -> a) -> a -> a 2 | foo f x = f $ x 3 | -------------------------------------------------------------------------------- /test/testdata/BrittanyCRLF.hs: -------------------------------------------------------------------------------- 1 | foo :: Int -> String-> IO () 2 | foo x y = do print x 3 | return 42 -------------------------------------------------------------------------------- /test/testdata/BrittanyLF.hs: -------------------------------------------------------------------------------- 1 | foo :: Int -> String-> IO () 2 | foo x y = do print x 3 | return 42 -------------------------------------------------------------------------------- /test/testdata/CodeActionImport.hs: -------------------------------------------------------------------------------- 1 | main :: IO () 2 | main = when True $ putStrLn "hello" -------------------------------------------------------------------------------- /test/testdata/CodeActionImportBrittany.hs: -------------------------------------------------------------------------------- 1 | import qualified Data.Maybe 2 | main :: IO () 3 | main = when True $ putStrLn "hello" -------------------------------------------------------------------------------- /test/testdata/CodeActionImportList.hs: -------------------------------------------------------------------------------- 1 | -- | Main entry point to the program 2 | main :: IO () 3 | main = 4 | when True 5 | $ hPutStrLn stdout 6 | $ fromMaybe "Good night, World!" (Just "Hello, World!") -------------------------------------------------------------------------------- /test/testdata/CodeActionImportListElaborate.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoImplicitPrelude #-} 2 | import System.IO (IO) 3 | import Data.List (find, head, last, tail, init, union, (\\), null, length, cons, uncons) 4 | -- | Main entry point to the program 5 | main :: IO () 6 | main = 7 | when True 8 | $ hPutStrLn stderr 9 | $ fromMaybe "Good night, World!" (Just "Hello, World!") -------------------------------------------------------------------------------- /test/testdata/CodeActionOnly.hs: -------------------------------------------------------------------------------- 1 | module CodeActionOnly where 2 | foo = bar 3 | where bar = id Nothing -------------------------------------------------------------------------------- /test/testdata/CodeActionRename.hs: -------------------------------------------------------------------------------- 1 | main = butStrLn "hello" 2 | foo = putStrn "world" 3 | -------------------------------------------------------------------------------- /test/testdata/FileWithWarning.hs: -------------------------------------------------------------------------------- 1 | 2 | main = putStrLn "hello" 3 | 4 | foo = x 5 | 6 | bar x = do 7 | return (3 + x) 8 | -------------------------------------------------------------------------------- /test/testdata/Format.hs: -------------------------------------------------------------------------------- 1 | module Format where 2 | foo :: Int -> Int 3 | foo 3 = 2 4 | foo x = x 5 | bar :: String -> IO String 6 | bar s = do 7 | x <- return "hello" 8 | return "asdf" 9 | 10 | data Baz = Baz { a :: Int, b :: String } 11 | 12 | -------------------------------------------------------------------------------- /test/testdata/FuncTest.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | main = putStrLn "hello" 4 | 5 | foo :: Int 6 | foo = bb 7 | 8 | bb = 5 9 | 10 | baz = do 11 | putStrLn "hello" 12 | 13 | f x = x+1 -------------------------------------------------------------------------------- /test/testdata/FuncTestError.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | main = putStrLn "hello" 4 | 5 | foo :: Int 6 | foo = bb 7 | 8 | bb = 5 9 | 10 | bug -- no hlint returned because of this, despite redundant do below 11 | 12 | baz = do 13 | putStrLn "hello" 14 | 15 | f x = x+1 16 | -------------------------------------------------------------------------------- /test/testdata/FuncTestFail.hs: -------------------------------------------------------------------------------- 1 | main :: IO Int 2 | main = return "yow 3 | -------------------------------------------------------------------------------- /test/testdata/GhcModCaseSplit.hs: -------------------------------------------------------------------------------- 1 | 2 | main = putStrLn "hello" 3 | 4 | foo :: Maybe Int -> () 5 | foo x = () 6 | -------------------------------------------------------------------------------- /test/testdata/HaReCase.hs: -------------------------------------------------------------------------------- 1 | 2 | main = putStrLn "hello" 3 | 4 | foo :: Int -> Int 5 | foo x = if odd x 6 | then 7 | x + 3 8 | else 9 | x 10 | 11 | -------------------------------------------------------------------------------- /test/testdata/HaReDemote.hs: -------------------------------------------------------------------------------- 1 | 2 | main = putStrLn "hello" 3 | 4 | foo x = y + 3 5 | 6 | y = 7 7 | -------------------------------------------------------------------------------- /test/testdata/HaReGA1/HaReGA1.cabal: -------------------------------------------------------------------------------- 1 | name: HaReGA1 2 | version: 0.1.0.0 3 | cabal-version: >=2.0 4 | build-type: Simple 5 | 6 | executable harega 7 | build-depends: base, parsec 8 | main-is: HaReGA1.hs 9 | default-language: Haskell2010 10 | 11 | -------------------------------------------------------------------------------- /test/testdata/HaReGA1/HaReGA1.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | import Text.ParserCombinators.Parsec 3 | 4 | parseStr :: CharParser () String 5 | parseStr = do 6 | char '"' 7 | str <- many1 (noneOf "\"") 8 | char '"' 9 | return str 10 | 11 | main = putStrLn "hello" 12 | -------------------------------------------------------------------------------- /test/testdata/HaReGA1/cabal.project: -------------------------------------------------------------------------------- 1 | packages: . 2 | -------------------------------------------------------------------------------- /test/testdata/HaReLift.hs: -------------------------------------------------------------------------------- 1 | module HaReLift where 2 | foo = bar 3 | where bar = "hello" -------------------------------------------------------------------------------- /test/testdata/HaReMoveDef.hs: -------------------------------------------------------------------------------- 1 | 2 | main = putStrLn "hello" 3 | 4 | lifting x = x + y 5 | where 6 | y = 4 7 | 8 | liftToTop x = x + y 9 | where 10 | y = z + 4 11 | where 12 | z = 7 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/testdata/HaReRename.hs: -------------------------------------------------------------------------------- 1 | 2 | main = putStrLn "hello" 3 | 4 | foo :: Int -> Int 5 | foo x = x + 3 6 | 7 | -------------------------------------------------------------------------------- /test/testdata/Highlight.hs: -------------------------------------------------------------------------------- 1 | module Highlight where 2 | foo :: Int 3 | foo = 3 4 | bar = foo 5 | where baz = let x = foo in x 6 | -------------------------------------------------------------------------------- /test/testdata/HlintNoRefactorings.hs: -------------------------------------------------------------------------------- 1 | main = putStrLn "hello" 2 | 3 | foo x = putStrLn x 4 | bar y = id 42 -------------------------------------------------------------------------------- /test/testdata/HlintParseFail.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TypeFamilies #-} 2 | {-# LANGUAGE GADTs #-} 3 | {-# LANGUAGE TypeOperators #-} 4 | {-# LANGUAGE DataKinds #-} 5 | {-# LANGUAGE TypeInType #-} 6 | module Test where 7 | 8 | import Data.Singletons.Prelude 9 | import Data.Singletons.TypeLits 10 | import Data.Type.Equality ((:~:) (..), (:~~:) (..)) 11 | 12 | data instance Sing (z :: (a :~: b)) where 13 | SRefl :: Sing Refl + 14 | -------------------------------------------------------------------------------- /test/testdata/HlintPragma.hs: -------------------------------------------------------------------------------- 1 | {-# ANN module ("hlint: ignore Redundant do" :: String) #-} 2 | 3 | main = do 4 | putStrLn ("hello") 5 | -------------------------------------------------------------------------------- /test/testdata/Hover.hs: -------------------------------------------------------------------------------- 1 | main :: IO Int 2 | main = return $ sum [1,2,3] 3 | -------------------------------------------------------------------------------- /test/testdata/References.hs: -------------------------------------------------------------------------------- 1 | main = return () 2 | 3 | foo = bar 4 | 5 | bar = let x = bar 42 in const "hello" 6 | 7 | baz = do 8 | x <- bar 23 9 | return $ bar 14 10 | -------------------------------------------------------------------------------- /test/testdata/Rename.hs: -------------------------------------------------------------------------------- 1 | main = do 2 | x <- return $ foo 42 3 | return (foo x) 4 | foo :: Int -> Int 5 | foo x = x + 1 6 | bar = (+ 1) . foo 7 | -------------------------------------------------------------------------------- /test/testdata/Symbols.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE PatternSynonyms #-} 2 | module Symbols where 3 | 4 | import Data.Maybe 5 | 6 | foo = bar 7 | where bar = 42 + dog 8 | where (dog, cat) = (1234, "meow") 9 | 10 | data MyData = A Int 11 | | B String 12 | 13 | pattern TestPattern :: Int -> MyData 14 | pattern TestPattern x = A x 15 | -------------------------------------------------------------------------------- /test/testdata/TopLevelSignature.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -Wall #-} 2 | module TopLevelSignature where 3 | main = do 4 | putStrLn "Hello" 5 | return () 6 | -------------------------------------------------------------------------------- /test/testdata/TypedHoles.hs: -------------------------------------------------------------------------------- 1 | module TypedHoles where 2 | foo :: [Int] -> Int 3 | foo x = _ -------------------------------------------------------------------------------- /test/testdata/TypedHoles2.hs: -------------------------------------------------------------------------------- 1 | module TypedHoles2 (foo2) where 2 | newtype A = A Int 3 | foo2 :: [A] -> A 4 | foo2 x = _ 5 | where 6 | stuff (A a) = A (a + 1) 7 | -------------------------------------------------------------------------------- /test/testdata/Types.hs: -------------------------------------------------------------------------------- 1 | module Types where 2 | 3 | import Control.Applicative 4 | 5 | foo :: Maybe Int -> Int 6 | foo (Just x) = x 7 | foo Nothing = 0 8 | 9 | bar :: Maybe Int -> Int 10 | bar x = case x of 11 | Just y -> y + 1 12 | Nothing -> 0 13 | 14 | maybeMonad :: Maybe Int -> Maybe Int 15 | maybeMonad x = do 16 | y <- x 17 | let z = return (y + 10) 18 | b <- z 19 | return (b + y) 20 | 21 | funcTest :: (a -> a) -> a -> a 22 | funcTest f a = f a 23 | 24 | compTest :: (b -> c) -> (a -> b) -> a -> c 25 | compTest f g = let h = f . g in h 26 | 27 | monadStuff :: (a -> b) -> IO a -> IO b 28 | monadStuff f action = f <$> action 29 | 30 | data Test 31 | = TestC Int 32 | | TestM String 33 | deriving (Show, Eq, Ord) -------------------------------------------------------------------------------- /test/testdata/UnusedTerm.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -Wall #-} 2 | module UnusedTerm () where 3 | imUnused :: Int -> Int 4 | imUnused 1 = 1 5 | imUnused 2 = 2 6 | imUnused _ = 3 7 | -------------------------------------------------------------------------------- /test/testdata/addPackageTest/cabal-exe/AddPackage.hs: -------------------------------------------------------------------------------- 1 | import Data.Text 2 | foo = pack "I'm a Text" 3 | main = putStrLn "hello" 4 | -------------------------------------------------------------------------------- /test/testdata/addPackageTest/cabal-exe/add-package-test.cabal: -------------------------------------------------------------------------------- 1 | name: add-package-test 2 | version: 0.1.0.0 3 | license: BSD3 4 | author: Luke Lau 5 | maintainer: luke_lau@icloud.com 6 | build-type: Simple 7 | extra-source-files: ChangeLog.md 8 | cabal-version: >=1.10 9 | 10 | executable AddPackage 11 | exposed-modules: ./. 12 | main-is: AddPackage.hs 13 | build-depends: base >=4.7 && <5 14 | default-language: Haskell2010 -------------------------------------------------------------------------------- /test/testdata/addPackageTest/cabal-lib/AddPackage.hs: -------------------------------------------------------------------------------- 1 | module AddPackage where 2 | 3 | import Data.Text 4 | foo = pack "I'm a Text" -------------------------------------------------------------------------------- /test/testdata/addPackageTest/cabal-lib/add-package-test.cabal: -------------------------------------------------------------------------------- 1 | name: add-package-test 2 | version: 0.1.0.0 3 | license: BSD3 4 | author: Luke Lau 5 | maintainer: luke_lau@icloud.com 6 | build-type: Simple 7 | extra-source-files: ChangeLog.md 8 | cabal-version: >=1.10 9 | 10 | library 11 | exposed-modules: AddPackage 12 | build-depends: base >=4.7 && <5 13 | -- hs-source-dirs: 14 | default-language: Haskell2010 15 | -------------------------------------------------------------------------------- /test/testdata/addPackageTest/hpack-exe/app/Asdf.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | import Codec.Compression.GZip 4 | 5 | main = return $ compress "hello" -------------------------------------------------------------------------------- /test/testdata/addPackageTest/hpack-exe/asdf.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 1.12 2 | 3 | -- This file has been generated from package.yaml by hpack version 0.32.0. 4 | -- 5 | -- see: https://github.com/sol/hpack 6 | -- 7 | -- hash: 69241e1f4f912f034502d225d2017f035c38062080733108c11cd3d111cb9007 8 | 9 | name: asdf 10 | version: 0.1.0.0 11 | description: Please see the README on GitHub at 12 | homepage: https://github.com/githubuser/asdf#readme 13 | bug-reports: https://github.com/githubuser/asdf/issues 14 | author: Author name here 15 | maintainer: example@example.com 16 | copyright: 2018 Author name here 17 | license: BSD3 18 | build-type: Simple 19 | extra-source-files: 20 | README.md 21 | ChangeLog.md 22 | 23 | source-repository head 24 | type: git 25 | location: https://github.com/githubuser/asdf 26 | 27 | executable asdf-exe 28 | main-is: Main.hs 29 | other-modules: 30 | Asdf 31 | Paths_asdf 32 | hs-source-dirs: 33 | app 34 | ghc-options: -threaded -rtsopts -with-rtsopts=-N 35 | build-depends: 36 | base >=4.7 && <5 37 | default-language: Haskell2010 38 | -------------------------------------------------------------------------------- /test/testdata/addPackageTest/hpack-exe/package.yaml: -------------------------------------------------------------------------------- 1 | name: asdf 2 | version: 0.1.0.0 3 | github: "githubuser/asdf" 4 | license: BSD3 5 | author: "Author name here" 6 | maintainer: "example@example.com" 7 | copyright: "2018 Author name here" 8 | 9 | extra-source-files: 10 | - README.md 11 | - ChangeLog.md 12 | 13 | # Metadata used when publishing your package 14 | # synopsis: Short description of your package 15 | # category: Web 16 | 17 | # To avoid duplicated efforts in documentation and dealing with the 18 | # complications of embedding Haddock markup inside cabal files, it is 19 | # common to point users to the README.md file. 20 | description: Please see the README on GitHub at 21 | 22 | dependencies: 23 | - base >= 4.7 && < 5 24 | 25 | executables: 26 | asdf-exe: 27 | main: Main.hs 28 | source-dirs: app 29 | ghc-options: 30 | - -threaded 31 | - -rtsopts 32 | - -with-rtsopts=-N -------------------------------------------------------------------------------- /test/testdata/addPackageTest/hpack-lib/app/Asdf.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Asdf where 4 | 5 | import Codec.Compression.GZip 6 | 7 | main = return $ compress "hello" -------------------------------------------------------------------------------- /test/testdata/addPackageTest/hpack-lib/package.yaml: -------------------------------------------------------------------------------- 1 | name: asdf 2 | version: 0.1.0.0 3 | github: "githubuser/asdf" 4 | license: BSD3 5 | author: "Author name here" 6 | maintainer: "example@example.com" 7 | copyright: "2018 Author name here" 8 | 9 | extra-source-files: 10 | - README.md 11 | - ChangeLog.md 12 | 13 | # Metadata used when publishing your package 14 | # synopsis: Short description of your package 15 | # category: Web 16 | 17 | # To avoid duplicated efforts in documentation and dealing with the 18 | # complications of embedding Haddock markup inside cabal files, it is 19 | # common to point users to the README.md file. 20 | description: Please see the README on GitHub at 21 | 22 | library: 23 | source-dirs: app 24 | dependencies: 25 | - base >= 4.7 && < 5 26 | -------------------------------------------------------------------------------- /test/testdata/addPackageTest/invalid/AddPackage.hs: -------------------------------------------------------------------------------- 1 | import Data.Text 2 | foo = pack "I'm a Text" -------------------------------------------------------------------------------- /test/testdata/addPragmas/NeedsPragmas.hs: -------------------------------------------------------------------------------- 1 | 2 | import GHC.Generics 3 | 4 | main = putStrLn "hello" 5 | 6 | type Foo = Int 7 | 8 | instance Show Foo where 9 | show x = undefined 10 | 11 | instance Show (Int,String) where 12 | show = undefined 13 | 14 | data FFF a = FFF Int String a 15 | deriving (Generic,Functor,Traversable) 16 | -------------------------------------------------------------------------------- /test/testdata/addPragmas/test.cabal: -------------------------------------------------------------------------------- 1 | name: test 2 | version: 0.1.0.0 3 | -- synopsis: 4 | -- description: 5 | license: BSD3 6 | author: Author name here 7 | maintainer: example@example.com 8 | copyright: 2017 Author name here 9 | category: Web 10 | build-type: Simple 11 | cabal-version: >=1.10 12 | 13 | executable p 14 | main-is: NeedsPragmas.hs 15 | hs-source-dirs: . 16 | build-depends: base >= 4.7 && < 5 17 | default-language: Haskell2010 18 | ghc-options: -Wall -------------------------------------------------------------------------------- /test/testdata/badProjects/cabal/Foo.hs: -------------------------------------------------------------------------------- 1 | module Foo where 2 | 3 | foo :: Int 4 | foo = 3 5 | -------------------------------------------------------------------------------- /test/testdata/badProjects/cabal/bad-cabal.cabal: -------------------------------------------------------------------------------- 1 | name: bad-cabal 2 | version: 0.1.0.0 3 | license: BSD3 4 | author: Alan Zimmerman 5 | maintainer: alan.zimm@gmail.com 6 | build-type: Simple 7 | extra-source-files: ChangeLog.md 8 | cabal-version: >=1.10 9 | 10 | library 11 | exposed-modules: Foo 12 | build-depends: base >=4.7 && <5 13 | -- missing dependency 14 | , does-not-exist 15 | -- hs-source-dirs: 16 | default-language: Haskell2010 17 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/implicit-exe/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/implicit-exe/cabal.project: -------------------------------------------------------------------------------- 1 | packages: ./ -------------------------------------------------------------------------------- /test/testdata/cabal-helper/implicit-exe/implicit-exe.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: >=1.10 2 | name: implicit-exe 3 | version: 0.1.0.0 4 | license-file: LICENSE 5 | build-type: Simple 6 | 7 | library 8 | exposed-modules: Lib 9 | hs-source-dirs: src 10 | build-depends: base 11 | default-language: Haskell2010 12 | 13 | 14 | executable implicit-exe 15 | main-is: src/Exe.hs 16 | build-depends: base, implicit-exe 17 | default-language: Haskell2010 -------------------------------------------------------------------------------- /test/testdata/cabal-helper/implicit-exe/src/Exe.hs: -------------------------------------------------------------------------------- 1 | 2 | import Lib (someFunc) 3 | 4 | main = someFunc -------------------------------------------------------------------------------- /test/testdata/cabal-helper/implicit-exe/src/Lib.hs: -------------------------------------------------------------------------------- 1 | module Lib (someFunc) where 2 | 3 | someFunc :: IO () 4 | someFunc = putStrLn "someFunc" 5 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/mono-repo/A/A.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: >=1.10 2 | name: A 3 | version: 0.1.0.0 4 | build-type: Simple 5 | 6 | library 7 | exposed-modules: MyLib 8 | build-depends: base 9 | default-language: Haskell2010 10 | 11 | executable A 12 | main-is: Main.hs 13 | other-modules: MyLib 14 | build-depends: base, A 15 | default-language: Haskell2010 16 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/mono-repo/A/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import qualified MyLib (someFunc) 4 | 5 | main :: IO () 6 | main = do 7 | putStrLn "Hello, Haskell!" 8 | MyLib.someFunc 9 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/mono-repo/A/MyLib.hs: -------------------------------------------------------------------------------- 1 | module MyLib (someFunc) where 2 | 3 | someFunc :: IO () 4 | someFunc = putStrLn "someFunc" 5 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/mono-repo/A/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/mono-repo/B/B.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: >=1.10 2 | name: B 3 | version: 0.1.0.0 4 | build-type: Simple 5 | 6 | library 7 | exposed-modules: MyLib 8 | build-depends: base 9 | default-language: Haskell2010 10 | 11 | executable B 12 | main-is: Main.hs 13 | other-modules: MyLib 14 | build-depends: base, B 15 | default-language: Haskell2010 16 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/mono-repo/B/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import qualified MyLib (someFunc) 4 | 5 | main :: IO () 6 | main = do 7 | putStrLn "Hello, Haskell!" 8 | MyLib.someFunc 9 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/mono-repo/B/MyLib.hs: -------------------------------------------------------------------------------- 1 | module MyLib (someFunc) where 2 | 3 | someFunc :: IO () 4 | someFunc = putStrLn "someFunc" 5 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/mono-repo/B/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/mono-repo/C/C.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: >=1.10 2 | name: C 3 | version: 0.1.0.0 4 | build-type: Simple 5 | 6 | library 7 | exposed-modules: MyLib 8 | build-depends: base 9 | default-language: Haskell2010 10 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/mono-repo/C/MyLib.hs: -------------------------------------------------------------------------------- 1 | module MyLib (someFunc) where 2 | 3 | someFunc :: IO () 4 | someFunc = putStrLn "someFunc" 5 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/mono-repo/C/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/mono-repo/cabal.project: -------------------------------------------------------------------------------- 1 | packages: 2 | ./A/ 3 | ./B/ 4 | ./C/ -------------------------------------------------------------------------------- /test/testdata/cabal-helper/multi-source-dirs/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/multi-source-dirs/multi-source-dirs.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: >=1.10 2 | name: multi-source-dirs 3 | version: 0.1.0.0 4 | license-file: LICENSE 5 | build-type: Simple 6 | 7 | library 8 | exposed-modules: Lib, BetterLib 9 | hs-source-dirs: src, src/input 10 | build-depends: base 11 | default-language: Haskell2010 12 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/multi-source-dirs/src/BetterLib.hs: -------------------------------------------------------------------------------- 1 | module BetterLib where 2 | 3 | 4 | foo = 3 5 | bar = "String" -------------------------------------------------------------------------------- /test/testdata/cabal-helper/multi-source-dirs/src/input/Lib.hs: -------------------------------------------------------------------------------- 1 | module Lib where 2 | 3 | foobar = 15 4 | 5 | fizbuzz :: Int -> String 6 | fizbuzz n = "Fizz" -------------------------------------------------------------------------------- /test/testdata/cabal-helper/simple-cabal/MyLib.hs: -------------------------------------------------------------------------------- 1 | module MyLib (someFunc) where 2 | 3 | someFunc :: IO () 4 | someFunc = putStrLn "someFunc" 5 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/simple-cabal/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/simple-cabal/simple-cabal-test.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: >=1.10 2 | name: simple-cabal-test 3 | version: 0.1.0.0 4 | license-file: LICENSE 5 | build-type: Simple 6 | 7 | library 8 | exposed-modules: MyLib 9 | build-depends: base 10 | default-language: Haskell2010 11 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/simple-stack/MyLib.hs: -------------------------------------------------------------------------------- 1 | module MyLib (someFunc) where 2 | 3 | someFunc :: IO () 4 | someFunc = putStrLn "someFunc" 5 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/simple-stack/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/simple-stack/simple-stack-test.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: >=1.10 2 | name: simple-stack-test 3 | version: 0.1.0.0 4 | license-file: LICENSE 5 | build-type: Simple 6 | 7 | library 8 | exposed-modules: MyLib 9 | build-depends: base 10 | default-language: Haskell2010 11 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/sub-package/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/sub-package/app/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import qualified MyLib (someFunc) 4 | 5 | main :: IO () 6 | main = do 7 | putStrLn "Hello, Haskell!" 8 | MyLib.someFunc 9 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/sub-package/plugins-api/PluginLib.hs: -------------------------------------------------------------------------------- 1 | module PluginLib (someFunc) where 2 | 3 | someFunc :: IO () 4 | someFunc = putStrLn "someFunc" 5 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/sub-package/plugins-api/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/sub-package/plugins-api/plugins-api.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: >=1.10 2 | name: plugins-api 3 | version: 0.1.0.0 4 | license-file: LICENSE 5 | build-type: Simple 6 | 7 | library 8 | exposed-modules: PluginLib 9 | build-depends: base 10 | default-language: Haskell2010 11 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/sub-package/src/MyLib.hs: -------------------------------------------------------------------------------- 1 | module MyLib (someFunc) where 2 | 3 | import qualified PluginLib as L 4 | 5 | someFunc :: IO () 6 | someFunc = L.someFunc 7 | -------------------------------------------------------------------------------- /test/testdata/cabal-helper/sub-package/sub-package.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: >=1.10 2 | name: sub-package 3 | version: 0.1.0.0 4 | license-file: LICENSE 5 | build-type: Simple 6 | 7 | library 8 | exposed-modules: MyLib 9 | build-depends: base, plugins-api 10 | hs-source-dirs: src 11 | default-language: Haskell2010 12 | 13 | executable sub-package 14 | main-is: Main.hs 15 | build-depends: base, sub-package 16 | hs-source-dirs: app 17 | default-language: Haskell2010 18 | -------------------------------------------------------------------------------- /test/testdata/completion/Completion.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | import Data.Maybe 3 | import qualified Data.List 4 | 5 | main :: IO () 6 | main = putStrLn "hello" 7 | 8 | foo :: Either a b -> Either a b 9 | foo = id -------------------------------------------------------------------------------- /test/testdata/completion/Context.hs: -------------------------------------------------------------------------------- 1 | module Context where 2 | import Control.Concurrent as Conc 3 | foo :: Int -> Int 4 | foo x = abs 42 -------------------------------------------------------------------------------- /test/testdata/completion/DupRecFields.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DuplicateRecordFields #-} 2 | module DupRecFields where 3 | 4 | newtype One = One { accessor :: Int } 5 | newtype Two = Two { accessor :: Int } 6 | -------------------------------------------------------------------------------- /test/testdata/completion/completions.cabal: -------------------------------------------------------------------------------- 1 | name: completions 2 | version: 0.1.0.0 3 | cabal-version: >= 2.0 4 | build-type: Simple 5 | 6 | executable compl-exe 7 | other-modules: DupRecFields, Context 8 | main-is: Completion.hs 9 | default-language: Haskell2010 10 | build-depends: base 11 | -------------------------------------------------------------------------------- /test/testdata/context/ExampleContext.hs: -------------------------------------------------------------------------------- 1 | module ExampleContext (foo) where 2 | 3 | import Data.List (find) 4 | import Control.Monad hiding (fix) 5 | 6 | foo :: Int -> Int 7 | foo xs = bar xs + 1 8 | where 9 | bar :: Int -> Int 10 | bar x = x + 2 11 | 12 | data Foo a = Foo a 13 | deriving (Show) 14 | 15 | class Bar a where 16 | bar :: a -> Integer 17 | 18 | instance Integral a => Bar (Foo a) where 19 | bar (Foo a) = toInteger a 20 | 21 | -------------------------------------------------------------------------------- /test/testdata/context/Foo/Bar.hs: -------------------------------------------------------------------------------- 1 | module Foo.Bar where 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/testdata/definition/Bar.hs: -------------------------------------------------------------------------------- 1 | module Bar where 2 | 3 | a = 42 4 | -------------------------------------------------------------------------------- /test/testdata/definition/Foo.hs: -------------------------------------------------------------------------------- 1 | module Foo (module Bar) where 2 | 3 | import Bar 4 | -------------------------------------------------------------------------------- /test/testdata/definition/definitions.cabal: -------------------------------------------------------------------------------- 1 | name: definitions 2 | version: 0.1.0.0 3 | cabal-version: >= 2.0 4 | build-type: Simple 5 | 6 | library 7 | exposed-modules: Foo 8 | other-modules: Bar 9 | default-language: Haskell2010 10 | build-depends: base 11 | -------------------------------------------------------------------------------- /test/testdata/gototest/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /test/testdata/gototest/app/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Lib 4 | import Lib2 5 | 6 | main :: IO () 7 | main = someFunc >> g 8 | -------------------------------------------------------------------------------- /test/testdata/gototest/cabal.project: -------------------------------------------------------------------------------- 1 | packages: . 2 | 3 | write-ghc-environment-files: never 4 | -------------------------------------------------------------------------------- /test/testdata/gototest/gototest.cabal: -------------------------------------------------------------------------------- 1 | name: gototest 2 | version: 0.1.0.0 3 | -- synopsis: 4 | -- description: 5 | license: BSD3 6 | author: Author name here 7 | maintainer: example@example.com 8 | copyright: 2017 Author name here 9 | category: Web 10 | build-type: Simple 11 | cabal-version: >=1.10 12 | 13 | executable gototest-exec 14 | hs-source-dirs: app 15 | main-is: Main.hs 16 | other-modules: 17 | build-depends: base >= 4.7 && < 5, gototest 18 | default-language: Haskell2010 19 | 20 | library 21 | hs-source-dirs: src 22 | exposed-modules: Lib, Lib2 23 | build-depends: base >= 4.7 && < 5 24 | default-language: Haskell2010 25 | -------------------------------------------------------------------------------- /test/testdata/gototest/src/Lib.hs: -------------------------------------------------------------------------------- 1 | module Lib 2 | 3 | where 4 | 5 | someFunc :: IO () 6 | someFunc = putStrLn "someFunc" 7 | 8 | data DataType = DataType Int 9 | 10 | dataTypeId :: DataType -> DataType 11 | dataTypeId dataType = dataType 12 | 13 | newtype NewType = NewType Int 14 | 15 | newTypeId :: NewType -> NewType 16 | newTypeId newType = newType 17 | 18 | data Enu = First | Second 19 | 20 | enuId :: Enu -> Enu 21 | enuId enu = enu 22 | 23 | toNum :: Enu -> Int 24 | toNum First = 1 25 | toNum Second = 2 26 | 27 | type MyInt = Int 28 | 29 | myIntId :: MyInt -> MyInt 30 | myIntId myInt = myInt 31 | 32 | type TypEnu = Enu 33 | 34 | typEnuId :: TypEnu -> TypEnu 35 | typEnuId enu = enu 36 | 37 | data Parameter a = Parameter a 38 | 39 | parameterId :: Parameter a -> Parameter a 40 | parameterId pid = pid -------------------------------------------------------------------------------- /test/testdata/gototest/src/Lib2.hs: -------------------------------------------------------------------------------- 1 | module Lib2 where 2 | 3 | import Lib 4 | 5 | g = do 6 | someFunc 7 | print x 8 | where z = 1+2 9 | y = z+z 10 | x = y*z 11 | 12 | otherId :: DataType -> DataType 13 | otherId dataType = dataType -------------------------------------------------------------------------------- /test/testdata/hieBiosError/Foo.hs: -------------------------------------------------------------------------------- 1 | main = putStrLn "hey" 2 | -------------------------------------------------------------------------------- /test/testdata/hieBiosMainIs/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | main :: IO () 4 | main = putStrLn "Hello, Haskell!" 5 | -------------------------------------------------------------------------------- /test/testdata/hieBiosMainIs/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /test/testdata/hieBiosMainIs/hieBiosMainIs.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: >=1.10 2 | name: hieBiosMainIs 3 | version: 0.1.0.0 4 | build-type: Simple 5 | executable hieBiosMainIs 6 | main-is: Main.hs 7 | build-depends: base >=4.12 && <4.13 8 | default-language: Haskell2010 9 | -------------------------------------------------------------------------------- /test/testdata/liquid/Evens.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | {-@ type Even = {v:Int | v mod 2 = 0} @-} 4 | 5 | {-@ weAreEven :: [Even] @-} 6 | weAreEven = [(0-10), (0-4), 0, 2, 666] 7 | 8 | {-@ notEven :: Even @-} 9 | notEven = 7 10 | 11 | {-@ isEven :: n:Nat -> {v:Bool | (v <=> (n mod 2 == 0))} @-} 12 | isEven :: Int -> Bool 13 | isEven 0 = True 14 | isEven 1 = False 15 | isEven n = not (isEven (n-1)) 16 | 17 | {-@ evens :: n:Nat -> [Even] @-} 18 | evens n = [i | i <- range 0 n, isEven i] 19 | 20 | {-@ range :: lo:Int -> hi:Int -> [{v:Int | (lo <= v && v < hi)}] / [hi -lo] @-} 21 | range lo hi 22 | | lo < hi = lo : range (lo+1) hi 23 | | otherwise = [] 24 | 25 | {-@ shift :: [Even] -> Even -> [Even] @-} 26 | shift xs k = [x + k | x <- xs] 27 | 28 | {-@ double :: [Nat] -> [Even] @-} 29 | double xs = [x + x | x <- xs] 30 | 31 | 32 | 33 | --- 34 | 35 | notEven :: Int 36 | weAreEven :: [Int] 37 | shift :: [Int] -> Int -> [Int] 38 | double :: [Int] -> [Int] 39 | range :: Int -> Int -> [Int] 40 | 41 | main = putStrLn "hello" 42 | -------------------------------------------------------------------------------- /test/testdata/redundantImportTest/src/CodeActionRedundant.hs: -------------------------------------------------------------------------------- 1 | module CodeActionRedundant where 2 | import Data.List 3 | main :: IO () 4 | main = putStrLn "hello" -------------------------------------------------------------------------------- /test/testdata/redundantImportTest/src/MultipleImports.hs: -------------------------------------------------------------------------------- 1 | module MultipleImports where 2 | import Data.Foldable 3 | import Data.Maybe 4 | foo :: Int 5 | foo = fromJust (Just 3) 6 | -------------------------------------------------------------------------------- /test/testdata/redundantImportTest/test.cabal: -------------------------------------------------------------------------------- 1 | name: test 2 | version: 0.1.0.0 3 | -- synopsis: 4 | -- description: 5 | license: BSD3 6 | author: Author name here 7 | maintainer: example@example.com 8 | copyright: 2017 Author name here 9 | category: Web 10 | build-type: Simple 11 | cabal-version: >=1.10 12 | 13 | library 14 | exposed-modules: CodeActionRedundant, MultipleImports 15 | hs-source-dirs: src 16 | build-depends: base >= 4.7 && < 5 17 | default-language: Haskell2010 18 | ghc-options: -Wall -fwarn-unused-imports -------------------------------------------------------------------------------- /test/testdata/testdata.cabal: -------------------------------------------------------------------------------- 1 | name: testdata 2 | version: 0.1.0.0 3 | cabal-version: >=2.0 4 | build-type: Simple 5 | 6 | executable applyrefact 7 | build-depends: base 8 | main-is: ApplyRefact.hs 9 | default-language: Haskell2010 10 | 11 | executable applyrefact2 12 | build-depends: base 13 | main-is: ApplyRefact2.hs 14 | default-language: Haskell2010 15 | 16 | executable codeactionrename 17 | build-depends: base 18 | main-is: CodeActionRename.hs 19 | default-language: Haskell2010 20 | 21 | executable hover 22 | build-depends: base 23 | main-is: Hover.hs 24 | default-language: Haskell2010 25 | 26 | executable symbols 27 | build-depends: base 28 | main-is: Symbols.hs 29 | default-language: Haskell2010 30 | 31 | 32 | executable applyrefact2 33 | build-depends: base 34 | main-is: ApplyRefact2.hs 35 | default-language: Haskell2010 36 | 37 | executable hlintpragma 38 | build-depends: base 39 | main-is: HlintPragma.hs 40 | default-language: Haskell2010 41 | 42 | executable harecase 43 | build-depends: base 44 | main-is: HaReCase.hs 45 | default-language: Haskell2010 46 | 47 | executable haredemote 48 | build-depends: base 49 | main-is: HaReDemote.hs 50 | default-language: Haskell2010 51 | 52 | executable haremovedef 53 | build-depends: base 54 | main-is: HaReMoveDef.hs 55 | default-language: Haskell2010 56 | 57 | executable harerename 58 | build-depends: base 59 | main-is: HaReRename.hs 60 | default-language: Haskell2010 61 | 62 | executable haregenapplicative 63 | build-depends: base 64 | , parsec 65 | main-is: HaReGA1.hs 66 | default-language: Haskell2010 67 | 68 | executable functests 69 | build-depends: base 70 | main-is: FuncTest.hs 71 | default-language: Haskell2010 72 | 73 | executable evens 74 | build-depends: base 75 | main-is: Evens.hs 76 | hs-source-dirs: liquid 77 | default-language: Haskell2010 78 | 79 | executable filewithwarning 80 | build-depends: base 81 | main-is: FileWithWarning.hs 82 | default-language: Haskell2010 83 | -------------------------------------------------------------------------------- /test/testdata/typedHoleDiag.txt: -------------------------------------------------------------------------------- 1 | • Found hole: _ :: Maybe T.Text 2 | • In the expression: _ 3 | In an equation for ‘extractHoles’: 4 | extractHoles diag 5 | | "Found hole:" `T.isInfixOf` diag = _ 6 | | otherwise = Nothing 7 | • Relevant bindings include 8 | diag :: T.Text 9 | (bound at /private/var/folders/zh/fqwj2cq95b7gbzs49fsq5drw0000gn/T/ghc-mod48138/GhcMod48135-416.hs:482:14) 10 | extractHoles :: T.Text -> Maybe T.Text 11 | (bound at /private/var/folders/zh/fqwj2cq95b7gbzs49fsq5drw0000gn/T/ghc-mod48138/GhcMod48135-416.hs:482:1) 12 | Valid substitutions include 13 | Nothing :: forall a. Maybe a 14 | (imported from ‘Data.Maybe’ at /private/var/folders/zh/fqwj2cq95b7gbzs49fsq5drw0000gn/T/ghc-mod48138/GhcMod48135-416.hs:24:1-27 15 | (and originally defined in ‘GHC.Base’)) 16 | mempty :: forall a. Monoid a => a 17 | (imported from ‘Prelude’ at /private/var/folders/zh/fqwj2cq95b7gbzs49fsq5drw0000gn/T/ghc-mod48138/GhcMod48135-416.hs:8:8-39 18 | (and originally defined in ‘GHC.Base’)) 19 | undefined :: forall (a :: TYPE r). 20 | GHC.Stack.Types.HasCallStack => 21 | a 22 | (imported from ‘Prelude’ at /private/var/folders/zh/fqwj2cq95b7gbzs49fsq5drw0000gn/T/ghc-mod48138/GhcMod48135-416.hs:8:8-39 23 | (and originally defined in ‘GHC.Err’)) 24 | GM.mzero :: forall (m :: * -> *). GM.MonadPlus m => forall a. m a 25 | (imported qualified from ‘GhcMod.Error’ at /private/var/folders/zh/fqwj2cq95b7gbzs49fsq5drw0000gn/T/ghc-mod48138/GhcMod48135-416.hs:37:1-56 26 | (and originally defined in ‘GHC.Base’)) -------------------------------------------------------------------------------- /test/testdata/typedHoleDiag2.txt: -------------------------------------------------------------------------------- 1 | • Found hole: _ :: A 2 | • In the expression: _ 3 | In an equation for ‘foo2’: 4 | foo2 x 5 | = _ 6 | where 7 | stuff (A a) = A (a + 1) 8 | • Relevant bindings include 9 | stuff :: A -> A (bound at test/testdata/TypedHoles2.hs:6:5) 10 | x :: [A] (bound at test/testdata/TypedHoles2.hs:4:6) 11 | foo2 :: [A] -> A (bound at test/testdata/TypedHoles2.hs:4:1) 12 | Valid substitutions include 13 | undefined :: forall (a :: TYPE r). 14 | GHC.Stack.Types.HasCallStack => 15 | a 16 | (imported from ‘Prelude’ at test/testdata/TypedHoles2.hs:1:8-18 17 | (and originally defined in ‘GHC.Err’)) 18 | -------------------------------------------------------------------------------- /test/testdata/typedHoleDiag3.txt: -------------------------------------------------------------------------------- 1 | • Found hole: _ :: t -> FilePath 2 | Where: ‘t’ is a rigid type variable bound by 3 | the inferred type of 4 | lintDockerfile :: [IgnoreRule] 5 | -> t 6 | -> IO (Either Language.Docker.Parser.Error [Rules.RuleCheck]) 7 | at app/Main.hs:(229,5)-(235,47) 8 | • In the expression: _ 9 | In the first argument of ‘Docker.parseFile’, namely 10 | ‘(_ dockerFile)’ 11 | In a stmt of a 'do' block: ast <- Docker.parseFile (_ dockerFile) 12 | • Relevant bindings include 13 | processedFile :: Either Language.Docker.Parser.Error Dockerfile 14 | -> Either Language.Docker.Parser.Error [Rules.RuleCheck] 15 | (bound at app/Main.hs:233:9) 16 | processRules :: Dockerfile -> [Rules.RuleCheck] 17 | (bound at app/Main.hs:234:9) 18 | ignoredRules :: Rules.RuleCheck -> Bool 19 | (bound at app/Main.hs:235:9) 20 | dockerFile :: t (bound at app/Main.hs:229:32) 21 | ignoreRules :: [IgnoreRule] (bound at app/Main.hs:229:20) 22 | lintDockerfile :: [IgnoreRule] 23 | -> t -> IO (Either Language.Docker.Parser.Error [Rules.RuleCheck]) 24 | (bound at app/Main.hs:229:5) 25 | (Some bindings suppressed; use -fmax-relevant-binds=N or -fno-max-relevant-binds) 26 | Valid substitutions include 27 | mempty :: forall a. Monoid a => a 28 | (imported from ‘Prelude’ at app/Main.hs:5:8-11 29 | (and originally defined in ‘GHC.Base’)) 30 | undefined :: forall (a :: TYPE r). 31 | GHC.Stack.Types.HasCallStack => 32 | a 33 | (imported from ‘Prelude’ at app/Main.hs:5:8-11 34 | (and originally defined in ‘GHC.Err’)) 35 | idm :: forall m. Monoid m => m 36 | (imported from ‘Options.Applicative’ at app/Main.hs:21:1-46 37 | (and originally defined in ‘Options.Applicative.Builder’)) 38 | -------------------------------------------------------------------------------- /test/testdata/wErrorTest/src/WError.hs: -------------------------------------------------------------------------------- 1 | module WError where 2 | main = undefined 3 | -------------------------------------------------------------------------------- /test/testdata/wErrorTest/test.cabal: -------------------------------------------------------------------------------- 1 | name: test 2 | version: 0.1.0.0 3 | -- synopsis: 4 | -- description: 5 | license: BSD3 6 | author: Author name here 7 | maintainer: example@example.com 8 | copyright: 2017 Author name here 9 | category: Web 10 | build-type: Simple 11 | cabal-version: >=1.10 12 | 13 | library 14 | exposed-modules: WError 15 | hs-source-dirs: src 16 | build-depends: base >= 4.7 && < 5 17 | default-language: Haskell2010 18 | ghc-options: -Wall -Werror 19 | -------------------------------------------------------------------------------- /test/testdata/wrapper/8.8.1/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /test/testdata/wrapper/8.8.1/cabal1.cabal: -------------------------------------------------------------------------------- 1 | -- Initial cabal1.cabal generated by cabal init. For further 2 | -- documentation, see http://haskell.org/cabal/users-guide/ 3 | 4 | name: cabal1 5 | version: 0.1.0.0 6 | -- synopsis: 7 | -- description: 8 | license: PublicDomain 9 | -- license-file: LICENSE 10 | author: Alan Zimmerman 11 | maintainer: alan.zimm@gmail.com 12 | -- copyright: 13 | -- category: 14 | build-type: Simple 15 | -- extra-source-files: 16 | -- cabal-helper for cabal 2.2/GHC 8.4 needs a cabal version >= 2 17 | cabal-version: >=2.0 18 | 19 | executable cabal1 20 | main-is: main.hs 21 | -- other-modules: 22 | -- other-extensions: 23 | build-depends: base >=4.6 && <5 24 | hs-source-dirs: src 25 | default-language: Haskell2010 -------------------------------------------------------------------------------- /test/testdata/wrapper/8.8.1/hie.yaml: -------------------------------------------------------------------------------- 1 | # TODO: generate this in test suite 2 | cradle: 3 | stack: -------------------------------------------------------------------------------- /test/testdata/wrapper/8.8.1/src/Foo/Bar.hs: -------------------------------------------------------------------------------- 1 | module Foo.Bar where 2 | 3 | baz = 6 4 | -------------------------------------------------------------------------------- /test/testdata/wrapper/8.8.1/src/main.hs: -------------------------------------------------------------------------------- 1 | -- | Testing that HaRe can find source files from a cabal file 2 | 3 | import qualified Foo.Bar as B 4 | 5 | main = putStrLn "foo" 6 | 7 | baz = 3 + B.baz 8 | -------------------------------------------------------------------------------- /test/testdata/wrapper/8.8.1/stack.yaml: -------------------------------------------------------------------------------- 1 | resolver: ghc-8.8.1 2 | -------------------------------------------------------------------------------- /test/testdata/wrapper/ghc/dummy: -------------------------------------------------------------------------------- 1 | Needed or else git won't track the directory -------------------------------------------------------------------------------- /test/testdata/wrapper/lts-14.18/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /test/testdata/wrapper/lts-14.18/cabal1.cabal: -------------------------------------------------------------------------------- 1 | -- Initial cabal1.cabal generated by cabal init. For further 2 | -- documentation, see http://haskell.org/cabal/users-guide/ 3 | 4 | name: cabal1 5 | version: 0.1.0.0 6 | -- synopsis: 7 | -- description: 8 | license: PublicDomain 9 | -- license-file: LICENSE 10 | author: Alan Zimmerman 11 | maintainer: alan.zimm@gmail.com 12 | -- copyright: 13 | -- category: 14 | build-type: Simple 15 | -- extra-source-files: 16 | -- cabal-helper for cabal 2.2/GHC 8.4 needs a cabal version >= 2 17 | cabal-version: >=2.0 18 | 19 | executable cabal1 20 | main-is: main.hs 21 | -- other-modules: 22 | -- other-extensions: 23 | build-depends: base >=4.6 && <5 24 | hs-source-dirs: src 25 | default-language: Haskell2010 -------------------------------------------------------------------------------- /test/testdata/wrapper/lts-14.18/hie.yaml: -------------------------------------------------------------------------------- 1 | # TODO: generate this in test suite 2 | cradle: 3 | stack: -------------------------------------------------------------------------------- /test/testdata/wrapper/lts-14.18/src/Foo/Bar.hs: -------------------------------------------------------------------------------- 1 | module Foo.Bar where 2 | 3 | baz = 6 4 | -------------------------------------------------------------------------------- /test/testdata/wrapper/lts-14.18/src/main.hs: -------------------------------------------------------------------------------- 1 | -- | Testing that HaRe can find source files from a cabal file 2 | 3 | import qualified Foo.Bar as B 4 | 5 | main = putStrLn "foo" 6 | 7 | baz = 3 + B.baz 8 | -------------------------------------------------------------------------------- /test/testdata/wrapper/lts-14.18/stack.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-14.18 2 | -------------------------------------------------------------------------------- /test/unit/DiffSpec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module DiffSpec where 3 | 4 | import Haskell.Ide.Engine.PluginUtils 5 | import Language.Haskell.LSP.Types 6 | import Test.Hspec 7 | 8 | dummyUri :: Uri 9 | dummyUri = Uri "/foo/bar" 10 | 11 | spec :: Spec 12 | spec = 13 | describe "diffText" $ 14 | it "generates deletions correctly" $ 15 | let old = "hello\nworld\nfoo\nbar" 16 | new = "hello\nworld\nbar" 17 | (WorkspaceEdit _ (Just (List [TextDocumentEdit _ (List [e])]))) = 18 | diffText' True (dummyUri, old) new IncludeDeletions 19 | in e `shouldBe` TextEdit (Range (Position 2 0) (Position 3 0)) "" -------------------------------------------------------------------------------- /test/unit/ExtensibleStateSpec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module ExtensibleStateSpec where 3 | 4 | import qualified Data.Text as T 5 | import Data.Typeable 6 | import Haskell.Ide.Engine.MonadTypes 7 | import Haskell.Ide.Engine.MonadFunctions 8 | import TestUtils 9 | import System.Directory 10 | import System.FilePath 11 | 12 | import Test.Hspec 13 | 14 | main :: IO () 15 | main = hspec spec 16 | 17 | spec :: Spec 18 | spec = do 19 | describe "ExtensibleState" extensibleStateSpec 20 | 21 | extensibleStateSpec :: Spec 22 | extensibleStateSpec = 23 | describe "stores and retrieves in the state" $ 24 | it "stores the first one" $ do 25 | cwd <- getCurrentDirectory 26 | let fp = cwd "test" "testdata" "File.hs" 27 | r <- runIGM testPlugins fp $ do 28 | r1 <- makeRequest "test" "cmd1" () 29 | r2 <- makeRequest "test" "cmd2" () 30 | return (r1,r2) 31 | fmap fromDynJSON (fst r) `shouldBe` IdeResultOk (Just "result:put foo" :: Maybe T.Text) 32 | fmap fromDynJSON (snd r) `shouldBe` IdeResultOk (Just "result:got:\"foo\"" :: Maybe T.Text) 33 | 34 | -- --------------------------------------------------------------------- 35 | 36 | testPlugins :: IdePlugins 37 | testPlugins = pluginDescToIdePlugins [testDescriptor "test"] 38 | 39 | testDescriptor :: PluginId -> PluginDescriptor 40 | testDescriptor plId = PluginDescriptor 41 | { pluginId = plId 42 | , pluginName = "testDescriptor" 43 | , pluginDesc = "PluginDescriptor for testing Dispatcher" 44 | , pluginCommands = [ 45 | PluginCommand "cmd1" "description" cmd1 46 | , PluginCommand "cmd2" "description" cmd2 47 | ] 48 | , pluginCodeActionProvider = Nothing 49 | , pluginDiagnosticProvider = Nothing 50 | , pluginHoverProvider = Nothing 51 | , pluginSymbolProvider = Nothing 52 | , pluginFormattingProvider = Nothing 53 | } 54 | 55 | -- --------------------------------------------------------------------- 56 | 57 | cmd1 :: () -> IdeGhcM (IdeResult T.Text) 58 | cmd1 () = do 59 | put (MS1 "foo") 60 | return (IdeResultOk (T.pack "result:put foo")) 61 | 62 | cmd2 :: () -> IdeGhcM (IdeResult T.Text) 63 | cmd2 () = do 64 | (MS1 v) <- get 65 | return (IdeResultOk (T.pack $ "result:got:" ++ show v)) 66 | 67 | newtype MyState1 = MS1 T.Text deriving Typeable 68 | 69 | instance ExtensionClass MyState1 where 70 | initialValue = MS1 "initial" 71 | 72 | -- --------------------------------------------------------------------- 73 | -------------------------------------------------------------------------------- /test/unit/GhcModPluginSpec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | module GhcModPluginSpec where 4 | 5 | import qualified Data.Map as Map 6 | import qualified Data.Set as S 7 | import qualified Data.Text as T 8 | import Haskell.Ide.Engine.Ghc 9 | import Haskell.Ide.Engine.MonadTypes 10 | import Haskell.Ide.Engine.Plugin.Generic 11 | import Haskell.Ide.Engine.Plugin.GhcMod 12 | import Haskell.Ide.Engine.PluginUtils 13 | import Language.Haskell.LSP.Types ( toNormalizedUri ) 14 | import System.Directory 15 | import TestUtils 16 | 17 | import Test.Hspec 18 | 19 | -- --------------------------------------------------------------------- 20 | 21 | main :: IO () 22 | main = hspec spec 23 | 24 | spec :: Spec 25 | spec = do 26 | describe "ghc-mod plugin" ghcmodSpec 27 | 28 | -- --------------------------------------------------------------------- 29 | 30 | testPlugins :: IdePlugins 31 | testPlugins = pluginDescToIdePlugins [ghcmodDescriptor "ghcmod"] 32 | 33 | -- --------------------------------------------------------------------- 34 | 35 | ghcmodSpec :: Spec 36 | ghcmodSpec = 37 | describe "ghc-mod plugin commands(old plugin api)" $ do 38 | it "runs the check command" $ withCurrentDirectory "./test/testdata" $ do 39 | fp <- makeAbsolute "./FileWithWarning.hs" 40 | let act = setTypecheckedModule arg 41 | arg = filePathToUri fp 42 | IdeResultOk (_,env) <- runSingle testPlugins fp act 43 | case env of 44 | [] -> return () 45 | [s] -> T.unpack s `shouldStartWith` "Loaded package environment from" 46 | ss -> fail $ "got:" ++ show ss 47 | let 48 | res = IdeResultOk $ 49 | (Diagnostics (Map.singleton (toNormalizedUri arg) (S.singleton diag)), env) 50 | diag = Diagnostic (Range (toPos (4,7)) 51 | (toPos (4,8))) 52 | (Just DsError) 53 | Nothing 54 | (Just "bios") 55 | "Variable not in scope: x" 56 | Nothing 57 | 58 | testCommand testPlugins fp act "ghcmod" "check" arg res 59 | 60 | 61 | -- ---------------------------------------------------------------------------- 62 | 63 | it "runs the type command, find type" $ withCurrentDirectory "./test/testdata" $ do 64 | fp <- makeAbsolute "HaReRename.hs" 65 | let uri = filePathToUri fp 66 | act = do 67 | _ <- setTypecheckedModule uri 68 | liftToGhc $ newTypeCmd (toPos (5,9)) uri 69 | arg = TP False uri (toPos (5,9)) 70 | res = IdeResultOk 71 | [ (Range (toPos (5,9)) (toPos (5,10)), "Int") 72 | , (Range (toPos (5,1)) (toPos (5,14)), "Int -> Int") 73 | ] 74 | 75 | testCommand testPlugins fp act "ghcmod" "type" arg res 76 | 77 | 78 | -- ---------------------------------------------------------------------------- 79 | 80 | -- it "runs the casesplit command" $ withCurrentDirectory "./test/testdata" $ do 81 | -- fp <- makeAbsolute "GhcModCaseSplit.hs" 82 | -- let uri = filePathToUri fp 83 | -- act = do 84 | -- _ <- setTypecheckedModule uri 85 | -- -- splitCaseCmd' uri (toPos (5,5)) 86 | -- splitCaseCmd uri (toPos (5,5)) 87 | -- arg = HP uri (toPos (5,5)) 88 | -- res = IdeResultOk $ WorkspaceEdit 89 | -- (Just $ H.singleton uri 90 | -- $ List [TextEdit (Range (Position 4 0) (Position 4 10)) 91 | -- "foo Nothing = ()\nfoo (Just x) = ()"]) 92 | -- Nothing 93 | -- testCommand testPlugins act "ghcmod" "casesplit" arg res 94 | -------------------------------------------------------------------------------- /test/unit/HooglePluginSpec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | {-# LANGUAGE ScopedTypeVariables #-} 3 | module HooglePluginSpec where 4 | 5 | import Control.Monad 6 | import Control.Monad.IO.Class 7 | import Data.Maybe 8 | import Haskell.Ide.Engine.MonadTypes 9 | import Haskell.Ide.Engine.Support.Hoogle 10 | import Hoogle 11 | import System.Directory 12 | import System.FilePath 13 | import Test.Hspec 14 | import TestUtils 15 | 16 | -- --------------------------------------------------------------------- 17 | 18 | main :: IO () 19 | main = hspec spec 20 | 21 | spec :: Spec 22 | spec = do 23 | describe "hoogle plugin" hoogleSpec 24 | 25 | -- --------------------------------------------------------------------- 26 | 27 | testPlugins :: IdePlugins 28 | testPlugins = pluginDescToIdePlugins [] 29 | 30 | dispatchRequestP :: IdeGhcM a -> IO a 31 | dispatchRequestP act = do 32 | cwd <- liftIO $ getCurrentDirectory 33 | runIGM testPlugins (cwd "test" "testdata" "File.hs") act 34 | 35 | -- --------------------------------------------------------------------- 36 | 37 | hoogleSpec :: Spec 38 | hoogleSpec = do 39 | describe "hoogle environment" $ 40 | it "Checks the default dababase location" $ do 41 | db <- defaultDatabaseLocation 42 | exists <- doesFileExist db 43 | unless exists $ hoogle ["generate"] 44 | describe "hoogle initialization" $ do 45 | it "initialization succeeds" $ do 46 | r <- dispatchRequestP initializeHoogleDb 47 | isJust r `shouldBe` True 48 | 49 | ---- --------------------------------- 50 | 51 | describe "hoogle plugin commands(new plugin api)" $ do 52 | it "runs the info command" $ do 53 | let req = liftToGhc $ info "head" 54 | r <- dispatchRequestP $ initializeHoogleDb >> req 55 | r `shouldBe` Right "```haskell\nhead :: [a] -> a\n```\nExtract the first element of a list, which must be non-empty.\n\n[More info](https://hackage.haskell.org/package/base/docs/Prelude.html#v:head)" 56 | 57 | -- --------------------------------- 58 | 59 | it "runs the lookup command" $ do 60 | let req = liftToGhc $ Haskell.Ide.Engine.Support.Hoogle.lookup 1 "[a] -> a" 61 | r <- dispatchRequestP $ initializeHoogleDb >> req 62 | r `shouldBe` Right ["Prelude head :: [a] -> a"] 63 | -------------------------------------------------------------------------------- /test/unit/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Test.Hspec.Runner 4 | import TestUtils 5 | import qualified Spec 6 | 7 | -- --------------------------------------------------------------------- 8 | 9 | main :: IO () 10 | main = do 11 | setupBuildToolFiles 12 | config <- getHspecFormattedConfig "unit" 13 | withFileLogging "main.log" $ hspecWith config $ Spec.spec 14 | 15 | -- main :: IO () 16 | -- main = do 17 | -- summary <- withFile "results.xml" WriteMode $ \h -> do 18 | -- let c = defaultConfig 19 | -- { configFormatter = xmlFormatter 20 | -- , configHandle = h 21 | -- } 22 | -- hspecWith c Spec.spec 23 | -- unless (summaryFailures summary == 0) $ 24 | -- exitFailure 25 | 26 | -- --------------------------------------------------------------------- 27 | 28 | -------------------------------------------------------------------------------- /test/unit/OptionsSpec.hs: -------------------------------------------------------------------------------- 1 | module OptionsSpec where 2 | 3 | import Prelude hiding (unzip) 4 | import Data.List.NonEmpty(unzip) 5 | import Data.Version (showVersion) 6 | import Test.Hspec 7 | import Options.Applicative 8 | import Haskell.Ide.Engine.Options(GlobalOpts(..), RunMode(..), ProjectLoadingOpts(..), optionParser) 9 | import System.Exit(ExitCode(..)) 10 | import Data.List(isPrefixOf) 11 | import Paths_haskell_ide_engine as HIE (version) 12 | 13 | main :: IO () 14 | main = hspec spec 15 | 16 | spec :: Spec 17 | spec = do 18 | let defaultGlobalOptions = GlobalOpts False Nothing Nothing False Nothing False (ProjectLoadingMode $ ProjectLoadingOpts False []) 19 | let getParseFailure (Failure x) = Just (renderFailure x "hie") 20 | getParseFailure _ = Nothing 21 | let sut = optionParser 22 | let parserInfo = info sut mempty 23 | let parserPrefs = prefs mempty 24 | let runSut :: [String] -> ParserResult GlobalOpts 25 | runSut = execParserPure parserPrefs parserInfo 26 | 27 | describe "cmd option parsing" $ do 28 | describe "compiler flag" $ do 29 | let input = ["--compiler"] 30 | let result = runSut input 31 | let (maybeMessage, maybeStatusCode) = unzip $ getParseFailure result 32 | 33 | it "should return ghc version" $ 34 | maybeMessage `shouldSatisfy` any ("ghc" `isPrefixOf`) 35 | it "should return exit code 0" $ 36 | maybeStatusCode `shouldBe` Just ExitSuccess 37 | 38 | describe "numeric version flag" $ do 39 | let input = ["--numeric-version"] 40 | let result = runSut input 41 | let (maybeMessage, maybeStatusCode) = unzip $ getParseFailure result 42 | 43 | it "should return version" $ 44 | maybeMessage `shouldBe` Just (showVersion HIE.version) 45 | it "shoud return exit code 0" $ 46 | maybeStatusCode `shouldBe` Just ExitSuccess 47 | 48 | describe "not providing arguments" $ do 49 | let input = [] 50 | let result = runSut input 51 | let maybeGlobalOptions = getParseResult result 52 | 53 | it "should result in default options" $ 54 | maybeGlobalOptions `shouldBe` Just defaultGlobalOptions 55 | 56 | describe "lsp flag" $ do 57 | let input = ["--lsp"] 58 | let result = runSut input 59 | let maybeGlobalOptions = getParseResult result 60 | 61 | it "should result in default lsp options" $ 62 | maybeGlobalOptions `shouldBe` Just (GlobalOpts False Nothing Nothing False Nothing False LspMode) 63 | 64 | describe "providing two unmatching arguments" $ do 65 | let input = ["--lsp", "--dry-run"] 66 | let result = runSut input 67 | let (maybeMessage, maybeStatusCode) = unzip $ getParseFailure result 68 | 69 | it "should return expected error message" $ 70 | maybeMessage `shouldSatisfy` any ("Invalid option `--dry-run'" `isPrefixOf`) 71 | it "should return error exit code 1" $ 72 | maybeStatusCode `shouldBe` Just (ExitFailure 1) 73 | -------------------------------------------------------------------------------- /test/unit/Spec.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -F -pgmF hspec-discover -optF --module-name=Spec #-} 2 | {- 3 | 4 | See https://github.com/hspec/hspec/tree/master/hspec-discover#readme 5 | to understand this module 6 | 7 | Or http://hspec.github.io/hspec-discover.html 8 | 9 | -} 10 | -------------------------------------------------------------------------------- /test/wrapper/HieWrapper.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Control.Monad.IO.Class (liftIO) 4 | import Haskell.Ide.Engine.Cradle (findLocalCradle) 5 | import Haskell.Ide.Engine.Version 6 | import Test.Hspec 7 | import System.Directory 8 | import System.FilePath 9 | import System.Process 10 | 11 | main :: IO () 12 | main = hspec $ 13 | describe "version checking" $ do 14 | it "picks up a stack.yaml with 8.8.1" $ 15 | withCurrentDirectory "test/testdata/wrapper/8.8.1" $ do 16 | d <- getCurrentDirectory 17 | cradle <- liftIO (findLocalCradle (d "File.hs")) 18 | getProjectGhcVersion cradle `shouldReturn` "8.8.1" 19 | it "picks up a stack.yaml with 8.6.5" $ 20 | withCurrentDirectory "test/testdata/wrapper/lts-14.18" $ do 21 | d <- getCurrentDirectory 22 | cradle <- liftIO (findLocalCradle (d "File.hs")) 23 | getProjectGhcVersion cradle `shouldReturn` "8.6.5" 24 | it "picks up whatever version of ghc is on this machine" $ 25 | withCurrentDirectory "test/testdata/wrapper/ghc" $ do 26 | d <- getCurrentDirectory 27 | cradle <- liftIO (findLocalCradle (d "File.hs")) 28 | ghcDisplayVer <- readCreateProcess (shell "ghc --version") "" 29 | ghcVer <- getProjectGhcVersion cradle 30 | init ghcDisplayVer `shouldEndWith` ghcVer 31 | 32 | 33 | -------------------------------------------------------------------------------- /update-index-state.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | 5 | status_message() { 6 | printf "\\033[0;32m%s\\033[0m\\n" "$1" 7 | } 8 | 9 | error_message() { 10 | printf "\\033[0;31m%s\\033[0m\\n" "$1" 11 | } 12 | 13 | SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )" 14 | CACHE_LOCATION="${HOME}/.cabal/packages/hackage.haskell.org/01-index.cache" 15 | 16 | if [ ! -f "${CACHE_LOCATION}" ] ; then 17 | error_message "${CACHE_LOCATION} does not exist, did you run 'cabal update'?" 18 | exit 1 19 | fi 20 | 21 | if [ ! -f "${SCRIPTPATH}/cabal.project" ] ; then 22 | error_message "Could not find ${SCRIPTPATH}/cabal.project, skipping index state update." 23 | exit 3 24 | fi 25 | 26 | cabal v2-update 27 | 28 | arch=$(getconf LONG_BIT) 29 | 30 | case "${arch}" in 31 | 32) 32 | byte_size=4 33 | magic_word="CABA1002" 34 | ;; 35 | 64) 36 | byte_size=8 37 | magic_word="00000000CABA1002" 38 | ;; 39 | *) 40 | error_message "Unknown architecture (long bit): ${arch}" 41 | exit 2 42 | ;; 43 | esac 44 | 45 | # This is the logic to parse the binary format of 01-index.cache. 46 | # The first word is a magic 'caba1002', the second one is the timestamp in unix epoch. 47 | # Better than copying the cabal-install source code. 48 | if [ "$(xxd -u -p -l${byte_size} -s 0 "${CACHE_LOCATION}")" != "${magic_word}" ] ; then 49 | error_message "Magic word does not match!" 50 | exit 4 51 | fi 52 | cache_timestamp=$(echo "ibase=16;obase=A;$(xxd -u -p -l${byte_size} -s ${byte_size} "${CACHE_LOCATION}")" | bc) 53 | 54 | # If we got junk from the binary file, this should fail. 55 | cache_date=$(date --utc --date "@${cache_timestamp}" "+%FT%TZ") 56 | 57 | 58 | status_message "Updating index state in ${SCRIPTPATH}/cabal.project" 59 | 60 | if grep -q "^index-state: .*" "${SCRIPTPATH}/cabal.project" ; then 61 | awk '/index-state:/ {gsub(/.*/, "index-state: '${cache_date}'")}; { print }' "${SCRIPTPATH}/cabal.project" > "${SCRIPTPATH}/cabal.project.tmp" 62 | mv "${SCRIPTPATH}/cabal.project.tmp" "${SCRIPTPATH}/cabal.project" 63 | else 64 | printf "index-state: %s\n" "${cache_date}" >> "${SCRIPTPATH}/cabal.project" 65 | fi 66 | 67 | --------------------------------------------------------------------------------