--- title: 📦 Intro date: 2018-05-24 --- I was fortunate enough to be accepted for the Haskell foundation for this year's Summer of Code, and the project I will be working on is with the [Haskell IDE Engine](https://github.com/haskell/haskell-ide-engine). From the repository description, the Haskell IDE Engine (hie) is the engine for Haskell IDE integration. Most interestingly, it acts as a server for the Language Server Protocol so it can provide rich Haskell support for any IDE or text editor that supports the protocol. It can give diagnostics, refactor code, search document symbols and tons of other neat stuff. I'll be working on a test framework that can simulate a session interacting with a client. [You can read more about it here.](https://summerofcode.withgoogle.com/projects/#6041896627994624) ## haskell-ide-engine The project kind of acts as the glue between LSP and the various coding tools in the Haskell ecosystem. It has a plugin API that's used for integrating fan favourites such as `ghc-mod`, `hlint` and `HaRE`. It's spread across multiple repositories: 1. **haskell-ide-engine** provides the I/O and communicates between the client and ghc-mod, as well as any plugins such as HaRE or brittany 2. **haskell-lsp** (and **haskell-lsp-types**) contain definitions for functions and types according to the [LSP specification](https://microsoft.github.io/language-server-protocol/specification) 3. **ghc-mod** is a separate tool that provides most of the analysis and diagnostics, but its tightly coupled with HIE. 4. **haskell-lsp-client** is a library for LSP clients that my mentor Alan pointed out, we plan to use it as a starting point for #5. 5. **haskell-lsp-test** will soon be the testing framework! ## IRC I've mostly been communicating in the `#haskell-ide-engine` room on freenode. It's been a while since I've used IRC, but I got round to setting up and running an IRC bouncer on my server (ZNC). Launching [Colloquy](http://colloquy.info) was a blast from the past, complete with pre-retina icons. But as it turns out it's [still actively developed on GitHub!](https://github.com/colloquy/colloquy). It's no longer distributed on the website, so I cloned the repository, created an archive with Xcode and then moved the `.app` to `/Applications`. ## Blog At the moment I'm using this makeshift bash script to blog: ```bash cat header.html > index.html for md in $(ls -tr *.md); do markdown $md >> index.html done cat footer.html >> index.html ``` ## Setup It took me a while to get the development environment set up. I started off by using VSCode and [vscode-hie-server](//github.com/alanz/vscode-hie-server) for the client. There was an issue on master that caused the LSP parser to fail with VSCode, so I created a [pull request](https://github.com/alanz/haskell-lsp/pull/81) for it. But I'm mainly a Vim user, so I tried out [vim-lsc](//github.com/natebosch/vim-lsc) and then eventually settled for [LanguageClient-neovim](https://github.com/autozimu/LanguageClient-neovim) which seems to support more LSP features. Here's my current `~/.vimrc` bindings for it ```vim let g:LanguageClient_serverCommands = { 'haskell': ['hie', '--lsp', '--debug', '-l', '/tmp/hie.log', '--vomit'] \ } nnoremap K :call LanguageClient#textDocument_hover() nnoremap gd :call LanguageClient#textDocument_definition() nnoremap gr :call LanguageClient#textDocument_rename() nnoremap ga :call LanguageClient#textDocument_codeAction() nnoremap gs :call LanguageClient#textDocument_documentSymbol() set completefunc=LanguageClient#complete ``` At one point I ended up getting strange errors from HIE when running it on haskell-lsp and haskell-ide-engine (very meta): ``` hie: : cannot satisfy -package-id HaRe-0.8.4.1-inplace: HaRe-0.8.4.1-inplace is unusable due to shadowed dependencies: base-4.11.1.0 Strfnsk-StrtgyLb-5.0.1.0-e162e946 cabal-helper-0.8.0.3-inplace containers-0.5.11.0 directory-1.3.1.5 ghc-8.4.2 ghc-xctprnt-0.5.6.1-3f0c080b ghc-mod-core-5.9.0.0-inplace hslggr-1.2.10-e253fcf2 mnd-cntrl-1.0.2.3-90183ebd syb-0.7-652252ef syz-0.2.0.0-ae4391c5 (use -v for more information) ``` After two days of repeated `rm -r ~/.stack .stack-work`, I learnt two important lessons when working with stack projects: 1. Double check with `ls -a` to make sure there are no `dist`, `dist-newstyle`, `.cabal.project.local` or `.ghc-environment`s lying around. These will fool `ghc-mod` into thinking into using cabal instead of stack. 2. You need to use a `hie` that was compiled with the same GHC version as your stack resolver. Turning on the hie wrapper in VSCode can automatically find it for you, otherwise you will need to specify it yourself. But once I got hie working, it was amazing. Being able to rename variables with two keystrokes, apply quick-fixes straight fresh from `hlint` and jump to symbols with fuzzy finding all from vim was a glorious feeling. Unfortunately this did not last for long as the second time I launched vim I got this [delightful bug](https://github.com/haskell/haskell-ide-engine/issues/562). It's an issue that lies all the way within `ghc` and only affects macOS on 8.4.2. It looks like it won't get fixed till the next 8.6 release either, which is due around August. It only affects modules that use the PatternSynonyms language extension, which `haskell-ide-engine` uses. I'm still trying various linker flags to see if there is a workaround, but for the meantime it means that I can't use `hie` on `hie` without swapping out the ghc-8.4.2 resolver for ghc-8.2. ## Starter PRs Here are some PRs so far: - [Preventing hie from showing quickfixes for hlint suggestions with no possible refactorings](https://github.com/haskell/haskell-ide-engine/pull/548) - [Fixes for](https://github.com/haskell/haskell-ide-engine/pull/525) [extraneous newlines](https://github.com/haskell/haskell-ide-engine/pull/563) being added with Brittany - [Restructuring the response and cache architecture](https://github.com/haskell/haskell-ide-engine/pull/568) to allow for deferred IDE responses The last one is still a work in progress, but here's a summary of how it came about and what's going down. - When trying out `haskell-lsp-client`, the document symbols request returned an empty list when run immediately after starting `hie`, unless a delay was added so that `hie` had time to load the module. - I tried submitting a PR to move the symbol request from the `IdeM` monad to the `IdeGhcM` monad - These two monads determine what thread they run on: `IdeM` is for internal requests and stuff, but `IdeGhcM` is for anything that goes through `ghc-mod`, which may take some time to run - This turned out to be a bad idea™ since putting it on `IdeGhcM` would cause the request to block whenever a large module was being compiled in the background. We want it to only wait for the module to load whenever there was no cache available, but serve the cache whenever possible. I owe all of my thanks to `wz1000` for noticing this and pointing me in the right direction. The agreed plan is this: Change the function that returns cached modules, `getCachedModule` to return not just a `Maybe` but a more descriptive ADT: ```haskell data CachedModuleResult = ModuleLoading | ModuleFailed String | ModuleCached CachedModule IsStale ``` Add a queue of actions that get executed whenever a module is finished loading: ```haskell data IdeState = IdeState { moduleCache :: GhcModuleCache -- | A queue of actions to be performed once a module is loaded , actionQueue :: Map.Map FilePath [CachedModule -> IdeM ()] ... } ``` Change `IdeResponse` to be a full blown ADT instead of a pattern, and add a new deferred type that the dispatcher can distinguish between and handle the queueing for: ```haskell -- | The IDE response, with the type of response it contains data IdeResponse a = IdeResponseOk a | IdeResponseDeferred FilePath (CachedModule -> IdeGhcM (IdeResponse a)) | IdeResponseFail IdeError ``` This is where I'm currently at. My head hurts and this is turning out to be a huge undertaking for such a small edge case. But as `wz1000` said: > there really is no better way to get to know a codebase than to tear it up Tomorrow the community bonding period ends, and the real coding begins. I've a lot to learn about pracitcal Haskell: I've lived a very sheltered life in university, far away from the IO monad. But I'm looking forward to working with my mentor Alan and the other lovely members of the Haskell community, and hopefully making the future of Haskell tooling a little better.