# static-ls static-ls ("static language server") is a [hie files](https://gitlab.haskell.org/ghc/ghc/-/wikis/hie-files) and [hiedb](https://github.com/wz1000/HieDb/) based language server heavily inspired by [halfsp](https://github.com/masaeedu/halfsp), which reads static project information to provide IDE functionality through the language server protocol. `static-ls` will not generate this information on its own and instead will rely on the user to generate this information via separate programs Supported static sources of information currently include: - hiefiles - hiedb The goal of `static-ls` is to provide a high-speed, low-memory solution for large projects for which [haskell-language-server](https://github.com/haskell/haskell-language-server) tends to take up too much memory on recompilation. [Haskell-language-server](https://github.com/haskell/haskell-language-server) is recommended if you are not experiencing these issues. `static-ls` is meant to work on enterprise size projects where aforementioned constraints can be an issue. `static-ls` tends to work better standalone as a code navigation tool since project edits require re-indexing of hie files but also works reasonably well for editing with a program such as [ghcid](https://github.com/ndmitchell/ghcid) to watch files for compilation and the `-fdefer-type-errors flag`. In the future we plan to use more sources of static information such as interface files to fetch documentation or ghcid's output to fetch diagnostics Currently only ghc 9.4.4 and 9.6.1 are explicitly supported but I'm happy to add support for other versions of ghc if desired ## Usage 1. Compile your project with ide info `-fwrite-ide-info` and `-hiedir .hiefiles` For a better UX, the following flags are *strongly* recommended. ``` - -fdefer-type-errors - -Werror=deferred-type-errors - -Werror=deferred-out-of-scope-variables - -fno-defer-typed-holes ``` These flags will allow hie files to be refreshed even if compilation fails to type check and will ensure that type check failures are still thrown as errors. - If you're using hpack you can add: ``` ghc-options: - -fwrite-ide-info - -hiedir .hiefiles - -fdefer-type-errors - -Werror=deferred-type-errors - -Werror=deferred-out-of-scope-variables - -fno-defer-typed-holes ``` to your `package.yaml`. See this project's `package.yaml` or `static-ls.cabal` for examples - You may instead add the following to your `cabal.project.local` file: ``` ignore-project: False program-options: ghc-options: -fdefer-type-errors -Werror=deferred-type-errors -Werror=deferred-out-of-scope-variables -fno-defer-typed-holes ``` 2. Index your project in hiedb running: ``` hiedb -D .hiedb index .hiefiles --src-base-dir . ``` from your workspace root. If you're on an older version of `hiedb` where the `--src-base-dir` argument is not available use: ``` hiedb -D .hiedb index .hiefiles ``` `entr` is also recommended if you want file watching functionality: ``` find -L .hiefiles | entr hiedb -D .hiedb index /_ ``` 3. Point your language client to the `static-ls` binary and begin editing! (See [Editor Setup](#editor-setup) for instructions if you're not sure how) [ghcid](https://github.com/ndmitchell/ghcid) is recommended to refresh hie files but compiling with `cabal build` should work as well ## Features `static-ls` supports the following lsp methods: - `textDocument/references` - Note that find references only works on top level definitions and can be slow for functions which are used frequently ![Find references](./docs/gifs/find-references.gif) - `textDocument/hover` - Provides type information and definition location on hover ![Type on hover](./docs/gifs/hover.gif) - `textDocument/definition` - Works on both local and top level definitions ![Find definition](./docs/gifs/find-definition.gif) ## Limitations - Must be compiled on the same version of ghc as the project - You will need to re-index your hie files once you edit your project ## Editor setup Instructions for editor setup ### neovim - coc.nvim call `:CocConfig` and copy the following in: ``` { "languageserver": { "static-ls": { "command": "static-ls", "rootPatterns": ["*.cabal", "stack.yaml", "cabal.project", "package.yaml", "hie.yaml"], "filetypes": ["haskell"] }, }, } ``` ### Visual Studio Code 1. Install the Haskell language extension ![Haskell Extension](./docs/imgs/vs-code-extension.png) 2. Open the extension settings ![Go to tsettings](./docs/imgs/vs-code-settings.png) 3. Scroll down until you see "Server Executable Path" and set the path to the path of your `static-ls` binary ![Set the language server executable path](./docs/imgs/vs-code-settings-executable-path.png) Alternatively you can also in your workspace's `./vscode/settings.json` you can use the following: ``` { "haskell.manageHLS": "PATH", "haskell.serverExecutablePath": "static-ls", "haskell.serverExtraArgs": "" } ``` (Note `haskell.serverExecutablePath` should be the path to your binary).