Haskell-language-server: Distributable binaries and install-less VS Code extension

Created on 13 Jun 2020  ·  81Comments  ·  Source: haskell/haskell-language-server

It's becoming increasingly obvious that one of the major turnoffs for newcomers is the manual installation. Since we're pulling in so many dependencies, and for a complete install of all the different versions this can take multiple hours. It's a problem that we've had in haskell-ide-engine, and has carried over to haskell-language-server.

One of the most promising solutions was the idea of static binaries. Much work has already been carried out to make haskell-ide-engine more portable, by removing data files in hlint and libexec runtime executables in cabal-helper. And now with haskell-language-server and ghcide, I am not aware of any major blockers.

I've started working on a GitHub Actions workflow to generate binaries of haskell-language-server, building across Linux, macOS and Windows for GHC 8.6 through to 8.10. It gets triggered whenever a new release is created, then after building the binaries uploads them to the release as assets.

My aim is to have the vscode-hie-server VS Code extension automatically download these binaries for the appropriate platform and GHC version on an ad-hoc basis. This way newcomers can simply just install the extension from the VS Code marketplace, create a .hs file and start coding – without the need to build ghcide/haskell-language-server from source, or even having to install Stack or Cabal.

The only prerequisite is that GHC still needs to be installed, for the GHC libdir that the GHC API uses. And more importantly, this libdir (usually /usr/local/lib/ghc-8.10.1/ or something like that) needs to be fetched on the fly for static binaries – currently (in the non-nix scenario) it is obtained via ghc-paths, which bakes the path the libdir at compile time. Unfortunately this path will be different on the GitHub Actions runners than it will be on the users machine, so we will have to go back to how haskell-ide-engine called ghc --print-libdir to get this on the fly:

https://github.com/haskell/haskell-ide-engine/blob/aca3241eb0ea00de171f791d48a4861820327132/hie-plugin-api/Haskell/Ide/Engine/Cradle.hs#L99-L131

ghc is cradle specific however – on Stack, it will be the ghc that it downloaded, whilst for Cabal it may depend on the --with-compiler flag. Therefore I thought it made sense to delegate this work to hie-bios. I have a patch for hie-bios which returns the libdir alongside the GHC flags, calling stack exec ghc and cabal v2-exec ghc as needed. Or just ghc --print-libdir if a direct cradle is being used

One last crazy idea might be to actually start shipping and downloading the GHC libraries, so that there are zero dependencies entirely. How feasible this actually is, I'm not sure.

HLS downloading binaries

build enhancement

Most helpful comment

I tried the artifacts at https://github.com/bubba/haskell-language-server/releases/tag/test-release-37 and they work great on NixOS!

Awesome work!!

All 81 comments

I'm testing out the releases here, on the branch https://github.com/bubba/haskell-language-server/tree/github-action-builds. A typical GitHub Actions run is here.

I haven't pushed any code to the vscode extension yet, but it's currently just querying the GitHub REST API to get the list of current releases. One minor note is that since it's making unauthenticated requests, it's rate limited to 60 requests per hour per IP address.

I've also added a new --project-ghc-version argument to haskell-language-server-wrapper, which consults the cradle and prints the project's GHC version, and then exits. The aim is that the vscode extension will download the wrapper first, call it with this argument to first get the project version, and then download the corresponding GHC version of haskell-language-server, if it isn't already downloaded

I have wanted this since day one, it's one of the (many) things that @chrisdone got completely right with intero. Reading this plan felt like every question that came to mind had already been answered in the paragraph below. Moving the libdir query to hie-bios feels right to me, and the --project-ghc-version wrapper is reasonable too.

Looking forward to this!!

Running binaries on NixOS can be a big pain. I would love to help make this work.

I am not aware of any major blockers.

Last "major" blocker is brittany. It uses ghc-paths as well to find the libdir for certain code-paths.
To fix this, the internal API can be used: https://hackage.haskell.org/package/brittany-0.12.1.1/docs/Language-Haskell-Brittany-Internal.html#v:pPrintModule
But we are missing some important bits, such as Anns from ghc-exactprint which are a bit hard to obtain.

That was the last blocker of static binaries in HIE. @jneira also had a full static binary pipeline ready with Azure Pipelines for the case we would solve it.

@pepeiborra I would be happy for your input on https://github.com/mpickering/hie-bios/issues/151.
I have discussed it with @mpickering before, but he wanted to wait a bit to see what is really required by different cradle types, such rules_haskell and obelisk, iirc.

Could we just exclude brittany? It's an AGPL odd-ball which is far from the most important part of HLS.

Yes we could, I would still like to have it fixed eventually.

The binaries on GitHub actions were built without the -fagpl flag passed to Cabal, so weren’t included in the first place anyway as far as I can tell — a quick strings search for the lib dir revealed nothing

As someone who just tried to setup hls on vscode yesterday, I'm a haskell noob, I can just say it is a painful experience.

Not only downloading and installing everything took a very huge amount of time (more than an hour), but looking at the logs of the installation I was seeing that:

-plenty of stuff was being downloaded up to 3 times (it's like the process of cloning and then executing the install script went on 3 times).

  • I was even downloading jQuery at some point, like...why?

https://i.imgur.com/R4O3jQf.png

  • why was everything being compiled from sources? I kept getting warnings in console about this or that library not respecting some import rule.

All in all it took between 1 and 2 hours on my 7200u powered machine to have what I consider very basic ide features.

I'm not here to speak with entitlement that I expect everythng to work flawlessly (even tho, that's my experience for much of the languages I tried in my life, old or new ones), just to give feedback, because every time I bring up haskell tooling (especially related to developer experience), there is a very strong survivorship bias from the people who went through it already or don't care.

@bubba thanks to take care of that, needed for so long.
github actions looks nice, no need for azure if they work.

hie-bios PR for GHC libdir is in https://github.com/mpickering/hie-bios/pull/207

FWIW, the JQuery dependency is mine, and it supports our fairly advanced profiling UI for the IDE. It's also cheap to compile. But the point still stands - the experience is not great.

I got an error

/nix/store/1zf4cnaaidjajwb4gx4mnkqc5dypkcdy-binutils-2.31.1/bin/ld.gold: error: /nix/store/mjvz9b02v42lngkn4dxal6n1xrv8wx9l-gcc-9.2.0/lib/gcc/x86_64-unknown-linux-gnu/9.2.0/crtbeginT.o: requires dynamic R_X86_64_32 reloc against '__TMC_END__' which may overflow at runtime; recompile with -fPIC

while trying to build a fully static hls binary. not sure what when wrong.

I think I'm using the wrong terminology here, truly -static builds fail for me too on a myriad of dependencies. It would be nice to figure out why this is happening at some point. These binaries that the CI is generating should just be clear of data files and hard coded paths

I was able to run the branch on NixOS by using VSCode in a FHS environment:

https://github.com/puffnfresh/nix-files/blob/2f32ccda86874ba453e3c3fe0e3cdb94469aeee7/custom-pkgs/vscode-env.nix#L9-L11

It would be great to have actual static binaries so that we didn't have to do that.

Things are coming along pretty well, and the VS Code extension should now be in a testable-enough state. If you're interested, it would be great if you could try out downloading the attached vsix and seeing if the downloading process works:

  1. Install the extension in VS Code via / => Install from VSIX...
  2. In the preferences, set the hie variant to haskell-language-server
  3. Make sure that hie executable path is also empty
  4. Make sure that there are no haskell-language-server/haskell-language-server-wrapper binaries on your path
  5. Open a project or .hs file!

vscode-hie-server-0.0.40.vsix.zip

@bubba I've had a go at making your branch generate actual static binaries. I've been successful at getting 8.10.1 after I made some patches for ghcup. Sadly the other builds segfault:

https://github.com/puffnfresh/haskell-language-server/releases/tag/puffnfresh-v42

But these run great even on NixOS. I'm kinda stuck on 8.8.3 and 8.6.5 - not sure how to debug a segfault on GitHub Actions.

The GitHub Action is missing Windows and macOS support, which I couldn't easily do without having a bunch of code duplication. I think the solution would be to extract out most of the workflow to a shell script might be the best approach:

https://github.com/puffnfresh/haskell-language-server/blob/715ea2b683fd3ed31dd32ffd107571ad70d91adb/.github/workflows/build.yml

@puffnfresh Nice! I'm not sure if GitHub Actions has any ssh debugging capabilities, but supposedly there are docker containers with the virtual environments. Maybe we can try downloading them and building hls from within it?
I just looked at one of the segfaults from the logs and it looks like it's coming from ghc-paths, so it's probably something going wrong in the setup script.
I'm trying out building this with the --enable-executable-static flag on my macOS machine locally to see how it fares

Fixed the extension on Windows where the binaries didn't have the .exe extension, cc @jneira
vscode-hie-server-0.0.40.vsix.zip

@bubba, really, thanks a TON for your builds. I just downloaded the linux binary here on Arch and can see --help works, so I can start hacking.

I like the language but I don't have the nerve to stand Haskell tooling, it's one of the worst experiences in the field of programming. I attempted Haskell like 3 or 4 times over the years and always exited burned out with this.

This time I'm being cautious. I'm not installing anything from package manager (except for ghcup-hs-bin except a global ghc for basic system hacking, I'm grabbing ghc and cabal from ghcup), you see, stack on Arch Linux has 168 haskell micro-package deps. If installed, it dominates the system updates when doing system upgrades, so, either with cabal or stack, I'm just grabbing their generic linux binaries that gladly are being provided by the respective project sites ghcup ftw.

I'm surely not building haskell-language-server either, so again, really thanks for this.

Also, I wholly agree with enricopolanski.

Okay, I could get a feel of the current state of the project and I'm giving up for now, giving it an year or so to mature. Gladly thanks to the binaries I'm much less frustrated.

See bellow.

Really sorry for throwing this here, really, but I don't have time for the beta test required, so grab the information if useful, I'm not digging further as I rarely dabble into Haskell:

Issue 1, no idea what's up with this error, it's always showing up (see EDIT bellow):

Started LSP server in 0.01s
[Error  - 3:16:50 AM] haskell-lsp:configuration parse error. RequestMessage {_jsonrpc = "2.0", _id = IdInt 0, _method = Initialize, _params = InitializeParams {_processId = Just 107872, _rootPath = Just "/home/francisco/Projects/samples/haskell/sample", _rootUri = Just (Uri {getUri = "file:///home/francisco/Projects/samples/haskell/sample"}), _initializationOptions = Just (Object (fromList [])), _capabilities = ClientCapabilities {_workspace = Just (WorkspaceClientCapabilities {_applyEdit = Just True, _workspaceEdit = Just (WorkspaceEditClientCapabilities {_documentChanges = Just True}), _didChangeConfiguration = Just (DidChangeConfigurationClientCapabilities {_dynamicRegistration = Just True}), _didChangeWatchedFiles = Just (DidChangeWatchedFilesClientCapabilities {_dynamicRegistration = Just True}), _symbol = Just (SymbolClientCapabilities {_dynamicRegistration = Just True, _symbolKind = Just (SymbolKindClientCapabilities {_valueSet = Just (List [SkFile,SkModule,SkNamespace,SkPackage,SkClass,SkMethod,SkProperty,SkField,SkConstructor,SkEnum,SkInterface,SkFunction,SkVariable,SkConstant,SkString,SkNumber,SkBoolean,SkArray,SkObject,SkKey,SkNull,SkEnumMember,SkStruct,SkEvent,SkOperator,SkTypeParameter])})}), _executeCommand = Just (ExecuteClientCapabilities {_dynamicRegistration = Just True}), _workspaceFolders = Just True, _configuration = Just True}), _textDocument = Just (TextDocumentClientCapabilities {_synchronization = Just (SynchronizationTextDocumentClientCapabilities {_dynamicRegistration = Just True, _willSave = Just True, _willSaveWaitUntil = Just True, _didSave = Just True}), _completion = Just (CompletionClientCapabilities {_dynamicRegistration = Just True, _completionItem = Just (CompletionItemClientCapabilities {_snippetSupport = Just True, _commitCharactersSupport = Just True, _documentationFormat = Just (List [MkMarkdown,MkPlainText]), _deprecatedSupport = Just True, _preselectSupport = Just True, _tagSupport = Nothing}), _completionItemKind = Just (CompletionItemKindClientCapabilities {_valueSet = Just (List [CiText,CiMethod,CiFunction,CiConstructor,CiField,CiVariable,CiClass,CiInterface,CiModule,CiProperty,CiUnit,CiValue,CiEnum,CiKeyword,CiSnippet,CiColor,CiFile,CiReference,CiFolder,CiEnumMember,CiConstant,CiStruct,CiEvent,CiOperator,CiTypeParameter])}), _contextSupport = Just True}), _hover = Just (HoverClientCapabilities {_dynamicRegistration = Just True, _contentFormat = Just (List [MkMarkdown,MkPlainText])}), _signatureHelp = Just (SignatureHelpClientCapabilities {_dynamicRegistration = Just True, _signatureInformation = Just (SignatureInformationClientCapabilities {documentationFormat = Nothing})}), _references = Just (ReferencesClientCapabilities {_dynamicRegistration = Just True}), _documentHighlight = Just (DocumentHighlightClientCapabilities {_dynamicRegistration = Just True}), _documentSymbol = Just (DocumentSymbolClientCapabilities {_dynamicRegistration = Just True, _symbolKind = Just (DocumentSymbolKindClientCapabilities {_valueSet = Just (List [SkFile,SkModule,SkNamespace,SkPackage,SkClass,SkMethod,SkProperty,SkField,SkConstructor,SkEnum,SkInterface,SkFunction,SkVariable,SkConstant,SkString,SkNumber,SkBoolean,SkArray,SkObject,SkKey,SkNull,SkEnumMember,SkStruct,SkEvent,SkOperator,SkTypeParameter])}), _hierarchicalDocumentSymbolSupport = Just True}), _formatting = Just (FormattingClientCapabilities {_dynamicRegistration = Just True}), _rangeFormatting = Just (RangeFormattingClientCapabilities {_dynamicRegistration = Just True}), _onTypeFormatting = Just (OnTypeFormattingClientCapabilities {_dynamicRegistration = Just True}), _definition = Just (DefinitionClientCapabilities {_dynamicRegistration = Just True}), _typeDefinition = Just (TypeDefinitionClientCapabilities {_dynamicRegistration = Just True}), _implementation = Just (ImplementationClientCapabilities {_dynamicRegistration = Just True}), _codeAction = Just (CodeActionClientCapabilities {_dynamicRegistration = Just True, _codeActionLiteralSupport = Just (CodeActionLiteralSupport {_codeActionKind = CodeActionKindClientCapabilities {_valueSet = List [CodeActionUnknown "",CodeActionQuickFix,CodeActionRefactor,CodeActionRefactorExtract,CodeActionRefactorInline,CodeActionRefactorRewrite,CodeActionSource,CodeActionSourceOrganizeImports]}})}), _codeLens = Just (CodeLensClientCapabilities {_dynamicRegistration = Just True}), _documentLink = Just (DocumentLinkClientCapabilities {_dynamicRegistration = Just True}), _colorProvider = Just (ColorProviderClientCapabilities {_dynamicRegistration = Just True}), _rename = Just (RenameClientCapabilities {_dynamicRegistration = Just True, _prepareSupport = Just True}), _publishDiagnostics = Just (PublishDiagnosticsClientCapabilities {_relatedInformation = Just True, _tagSupport = Just (PublishDiagnosticsTagsClientCapabilities {_valueSet = List [DtUnnecessary,DtDeprecated]})}), _foldingRange = Just (FoldingRangeClientCapabilities {_dynamicRegistration = Just True, _rangeLimit = Just 5000, _lineFoldingOnly = Just True})}), _window = Just (WindowClientCapabilities {_workDoneProgress = Just True}), _experimental = Nothing}, _trace = Just TraceOff, _workspaceFolders = Just (List [WorkspaceFolder {_uri = "file:///home/francisco/Projects/samples/haskell/sample", _name = "sample"}])}} "key \"languageServerHaskell\" not found" 

Issue 2:

Project GHC version: 8.8.3

haskell-language-server exe candidates: ["
haskell-language-server-8.8.3\n","haskell-language-server-8.8","haskel
l-language-server"]

The wrapper is getting the GHC version number with a newline character at the end, so it always fail to find a binary with full name like haskell-language-server-8.8.3, I have circumvented the issue by creating a haskell-language-server-8.8 symlink, as the wrapper attempts that too.

Besides that, the server seems to be functional (I'm running it through coc.nvim on Linux).

EDIT:

Looks like issue 1 was happening because I didn't provide initializationOptions. I didn't provide one because there was nothing to configure, so I thought simply removing would have the same effect as "initializationOptions": {"languageServerHaskell": {}}.

@oblitum thanks for the info, this is all good stuff. Just to confirm you're downloading these binaries yourself and using another language client?
Good catch with the newline in the wrapper, will fix that now. The initializationOptions part definitely sounds like a bug within hls itself, it's an optional field in the specification so we shouldn't be failing to parse it

@bubba Yes, I downloaded, extracted and renamed them appropriately and have put them in ~/.local/bin. It's working on Vim/NeoVim just fine. It looked like the issue with the newline is present if current ghc in PATH is 8.10.1. I noticed the output changed when changing to 8.8.3 with ghcup set and removing 8.10.1, though setting an older one makes the wrapper/server not work when editing standalone haskell files, because it resolves to use 8.10.1, while it's not present (looks hard-coded or something due to the ghc the wrapper/server was compiled with), so I removed 8.8.3 from ghcup and put the 8.10.1 back, despite the newline character issue, which can be easily circumvented.

Another thing that is bad with the wrapper is the logger, at least with coc.nvim, for some reason the output comes full of line breaks on :CocInfo:

## Output channel: languageserver.haskell-language-server-wrapper

Run entered for haskell-language-server-wrapper(haskell-language-serve
r-wrapper) Version 0.1.0.0, Git revision edf2cc514b914b4883d2409b73d61
f62b5f61ef9 (dirty) 
x86_64 ghc-8.10.1
Current d
irectory: /home/francisco/Projects/samples/haskell
Operating system: l
inu
x
Argume
nts: ["--lsp"]
Cradle dire
ctory: /home/francisco
/Projects/samples/haske
ll
Cradle type: De
fault
Consulting the
 cradle to get project G
HC version...
Project GHC version: 8.10.1

haskell-language-server exe candidates: [
"haskell-language-server-8.10.1\n","haskell-language-server-8.10","has
kell-language-server"]
Launching haskell-language-server exe at:/home/
francisco/.local/bin/haskell-language-server-8.10
ghcide version: 0.1.
0.0 (GHC: 8.10.1) (PATH: /home/f
rancisco/.local/bin/haskell-language-server-8.10.1) (GIT hash: edf2cc514b9
14b4883d2409b73d61f62b5f61ef9)
Sta
rting (haskell-language-server)LSP server...
  with arguments: Argumen
ts {argLSP = True, argsCwd = Nothing, argFiles = [], argsVersion = Fal
se, argsShakeProfiling = Nothing, argsTesting = False, argsExamplePlug
in = False, argsDebugOn = False, argsLogFile = Nothing, argsThreads = 
0, argsProjectGhcVersion = False}
  with plugins: [PluginId "floskell",Pl
uginId "ghcide",PluginId "ormolu",PluginId "pragmas"]
  in directory: 
/home/francisco/Projects/samples/haskell
If you are seeing this in a t
erminal, you probably sh
ould have run ghcide WITHOUT the --lsp option!
 Started LSP server in 
0.01s
2020-06-29 11:38:16.217824193 [ThreadId 18] - Opened text document: file:///home/francisco/Projects/samples/haskell/Main.hs
Consulting the cradle for "/home/francisco/Projects/samples/haskell/Main.hs"
Right (ComponentOptions {componentOptions = [], componentRoot = "/home/francisco/Projects/samples/haskell", componentDependencies = []})
"Making new HscEnv[main]"
(([],Just HscEnvEq 3),fromList [])
2020-06-29 11:38:16.318527129 [ThreadId 92] - finish: FileStoreTC (took 0.10s)
2020-06-29 11:38:16.320197621 [ThreadId 133] - finish: InitialLoad (took 0.00s)

@oblitum I'm not too concerned about the line breaks issue, I assume this is just some weird buffering thing. But the standalone files not resolving to the correct ghc version on the path I would be quite worried about.
On standalone files the wrapper should never try to use the version of ghc it was compiled with, and it should try to use the server corresponding to whatever version ghc --numeric-version spits back, with the ghc being the one on the PATH. I presume ghcup set sets the ghc on the PATH to a certain version?
I'm currently building some new releases that use a slightly newer version of hie-bios which handles all this ghc version stuff. Once its done would you be able to give it a try? Thanks so much for helping test this

@bubba sure, sure, I can help at that, it's just some download and checking up info, there's no pain in that.

One thing left to figure out is why the window builds sometimes intermittently fail when building floskell or haskell-lsp-types. Could this be a memory issue? cc @jneira

@oblitum the linux binaries should be done now, could you check to see that haskell-language-server-wrapper is selecting the right ghc versions on standalone binaries, and that it's no longer adding in newlines? https://github.com/bubba/haskell-language-server/releases/tag/test-release-30

Sorry, those errors without any message are too frequent in windows but it is hard to trace the cause. They usually are not reproduced in a second try so people sometimes does an ugly cabal build || cabal build

@bubba just downloaded them to my PATH, but now it simply stopped working with the following:

[coc.nvim] request error. RequestMessage {_jsonrpc = "2.0", _id = IdInt 0, _method = Initialize, _params = InitializeParams {_processId = Just 307484, _rootPath = Just "/home/francisco/Projects/samples/haskell", _rootUri = Just (Uri {getUri = "file:///home/francisco/Projects/samples/haskell"}), _initializationOptions = Just (Object (fromList [("languageServerHaskell",Object (fromList []))])), _capabilities = ClientCapabilities {_workspace = Just (WorkspaceClientCapabilities {_applyEdit = Just True, _workspaceEdit = Just (WorkspaceEditClientCapabilities {_documentChanges = Just True}), _didChangeConfiguration = Just (DidChangeConfigurationClientCapabilities {_dynamicRegistration = Just True}), _didChangeWatchedFiles = Just (DidChangeWatchedFilesClientCapabilities {_dynamicRegistration = Just True}), _symbol = Just (SymbolClientCapabilities {_dynamicRegistration = Just True, _symbolKind = Just (SymbolKindClientCapabilities {_valueSet = Just (List [SkFile,SkModule,SkNamespace,SkPackage,SkClass,SkMethod,SkProperty,SkField,SkConstructor,SkEnum,SkInterface,SkFunction,SkVariable,SkConstant,SkString,SkNumber,SkBoolean,SkArray,SkObject,SkKey,SkNull,SkEnumMember,SkStruct,SkEvent,SkOperator,SkTypeParameter])})}), _executeCommand = Just (ExecuteClientCapabilities {_dynamicRegistration = Just True}), _workspaceFolders = Just True, _configuration = Just True}), _textDocument = Just (TextDocumentClientCapabilities {_synchronization = Just (SynchronizationTextDocumentClientCapabilities {_dynamicRegistration = Just True, _willSave = Just True, _willSaveWaitUntil = Just True, _didSave = Just True}), _completion = Just (CompletionClientCapabilities {_dynamicRegistration = Just True, _completionItem = Just (CompletionItemClientCapabilities {_snippetSupport = Just True, _commitCharactersSupport = Just True, _documentationFormat = Just (List [MkMarkdown,MkPlainText]), _deprecatedSupport = Just True, _preselectSupport = Just True, _tagSupport = Nothing}), _completionItemKind = Just (CompletionItemKindClientCapabilities {_valueSet = Just (List [CiText,CiMethod,CiFunction,CiConstructor,CiField,CiVariable,CiClass,CiInterface,CiModule,CiProperty,CiUnit,CiValue,CiEnum,CiKeyword,CiSnippet,CiColor,CiFile,CiReference,CiFolder,CiEnumMember,CiConstant,CiStruct,CiEvent,CiOperator,CiTypeParameter])}), _contextSupport = Just True}), _hover = Just (HoverClientCapabilities {_dynamicRegistration = Just True, _contentFormat = Just (List [MkMarkdown,MkPlainText])}), _signatureHelp = Just (SignatureHelpClientCapabilities {_dynamicRegistration = Just True, _signatureInformation = Just (SignatureInformationClientCapabilities {documentationFormat = Nothing})}), _references = Just (ReferencesClientCapabilities {_dynamicRegistration = Just True}), _documentHighlight = Just (DocumentHighlightClientCapabilities {_dynamicRegistration = Just True}), _documentSymbol = Just (DocumentSymbolClientCapabilities {_dynamicRegistration = Just True, _symbolKind = Just (DocumentSymbolKindClientCapabilities {_valueSet = Just (List [SkFile,SkModule,SkNamespace,SkPackage,SkClass,SkMethod,SkProperty,SkField,SkConstructor,SkEnum,SkInterface,SkFunction,SkVariable,SkConstant,SkString,SkNumber,SkBoolean,SkArray,SkObject,SkKey,SkNull,SkEnumMember,SkStruct,SkEvent,SkOperator,SkTypeParameter])}), _hierarchicalDocumentSymbolSupport = Just True}), _formatting = Just (FormattingClientCapabilities {_dynamicRegistration = Just True}), _rangeFormatting = Just (RangeFormattingClientCapabilities {_dynamicRegistration = Just True}), _onTypeFormatting = Just (OnTypeFormattingClientCapabilities {_dynamicRegistration = Just True}), _definition = Just (DefinitionClientCapabilities {_dynamicRegistration = Just True}), _typeDefinition = Just (TypeDefinitionClientCapabilities {_dynamicRegistration = Just True}), _implementation = Just (ImplementationClientCapabilities {_dynamicRegistration = Just True}), _codeAction = Just (CodeActionClientCapabilities {_dynamicRegistration = Just True, _codeActionLiteralSupport = Just (CodeActionLiteralSupport {_codeActionKind = CodeActionKindClientCapabilities {_valueSet = List [CodeActionUnknown "",CodeActionQuickFix,CodeActionRefactor,CodeActionRefactorExtract,CodeActionRefactorInline,CodeActionRefactorRewrite,CodeActionSource,CodeActionSourceOrganizeImports]}})}), _codeLens = Just (CodeLensClientCapabilities {_dynamicRegistration = Just True}), _documentLink = Just (DocumentLinkClientCapabilities {_dynamicRegistration = Just True}), _colorProvider = Just (ColorProviderClientCapabilities {_dynamicRegistration = Just True}), _rename = Just (RenameClientCapabilities {_dynamicRegistration = Just True, _prepareSupport = Just True}), _publishDiagnostics = Just (PublishDiagnosticsClientCapabilities {_relatedInformation = Just True, _tagSupport = Just (PublishDiagnosticsTagsClientCapabilities {_valueSet = List [DtUnnecessary,DtDeprecated]})}), _foldingRange = Just (FoldingRangeClientCapabilities {_dynamicRegistration = Just True, _rangeLimit = Just 5000, _lineFoldingOnly = Just True})}), _window = Just (WindowClientCapabilities {_workDoneProgress = Just True}), _experimental = Nothing}, _trace = Just TraceOff, _workspaceFolders = Just (List [WorkspaceFolder {_uri = "file:///home/francisco/Projects/samples/haskell", _name = "haskell"}])}} GHC installation not found in libdir: /opt/ghc/8.10.1/lib/ghc-8.10.1

[coc.nvim] Server languageserver.haskell-language-server-wrapper failed to start: Error: request error. RequestMessage {_jsonrpc = "2.0", _id = IdInt 0, _method = Initialize, _params = InitializeParams {_processId = Just 307484, _rootPath = Just "/home/francisco/Projects/samples/haskell", _rootUri = Just (Uri {getUri = "file:///home/francisco/Projects/samples/haskell"}), _initializationOptions = Just (Object (fromList [("languageServerHaskell",Object (fromList []))])), _capabilities = ClientCapabilities {_workspace = Just (WorkspaceClientCapabilities {_applyEdit = Just True, _workspaceEdit = Just (WorkspaceEditClientCapabilities {_documentChanges = Just True}), _didChangeConfiguration = Just (DidChangeConfigurationClientCapabilities {_dynamicRegistration = Just True}), _didChangeWatchedFiles = Just (DidChangeWatchedFilesClientCapabilities {_dynamicRegistration = Just True}), _symbol = Just (SymbolClientCapabilities {_dynamicRegistration = Just True, _symbolKind = Just (SymbolKindClientCapabilities {_valueSet = Just (List [SkFile,SkModule,SkNamespace,SkPackage,SkClass,SkMethod,SkProperty,SkField,SkConstructor,SkEnum,SkInterface,SkFunction,SkVariable,SkConstant,SkString,SkNumber,SkBoolean,SkArray,SkObject,SkKey,SkNull,SkEnumMember,SkStruct,SkEvent,SkOperator,SkTypeParameter])})}), _executeCommand = Just (ExecuteClientCapabilities {_dynamicRegistration = Just True}), _workspaceFolders = Just True, _configuration = Just True}), _textDocument = Just (TextDocumentClientCapabilities {_synchronization = Just (SynchronizationTextDocumentClientCapabilities {_dynamicRegistration = Just True, _willSave = Just True, _willSaveWaitUntil = Just True, _didSave = Just True}), _completion = Just (CompletionClientCapabilities {_dynamicRegistration = Just True, _completionItem = Just (CompletionItemClientCapabilities {_snippetSupport = Just True, _commitCharactersSupport = Just True, _documentationFormat = Just (List [MkMarkdown,MkPlainText]), _deprecatedSupport = Just True, _preselectSupport = Just True, _tagSupport = Nothing}), _completionItemKind = Just (CompletionItemKindClientCapabilities {_valueSet = Just (List [CiText,CiMethod,CiFunction,CiConstructor,CiField,CiVariable,CiClass,CiInterface,CiModule,CiProperty,CiUnit,CiValue,CiEnum,CiKeyword,CiSnippet,CiColor,CiFile,CiReference,CiFolder,CiEnumMember,CiConstant,CiStruct,CiEvent,CiOperator,CiTypeParameter])}), _contextSupport = Just True}), _hover = Just (HoverClientCapabilities {_dynamicRegistration = Just True, _contentFormat = Just (List [MkMarkdown,MkPlainText])}), _signatureHelp = Just (SignatureHelpClientCapabilities {_dynamicRegistration = Just True, _signatureInformation = Just (SignatureInformationClientCapabilities {documentationFormat = Nothing})}), _references = Just (ReferencesClientCapabilities {_dynamicRegistration = Just True}), _documentHighlight = Just (DocumentHighlightClientCapabilities {_dynamicRegistration = Just True}), _documentSymbol = Just (DocumentSymbolClientCapabilities {_dynamicRegistration = Just True, _symbolKind = Just (DocumentSymbolKindClientCapabilities {_valueSet = Just (List [SkFile,SkModule,SkNamespace,SkPackage,SkClass,SkMethod,SkProperty,SkField,SkConstructor,SkEnum,SkInterface,SkFunction,SkVariable,SkConstant,SkString,SkNumber,SkBoolean,SkArray,SkObject,SkKey,SkNull,SkEnumMember,SkStruct,SkEvent,SkOperator,SkTypeParameter])}), _hierarchicalDocumentSymbolSupport = Just True}), _formatting = Just (FormattingClientCapabilities {_dynamicRegistration = Just True}), _rangeFormatting = Just (RangeFormattingClientCapabilities {_dynamicRegistration = Just True}), _onTypeFormatting = Just (OnTypeFormattingClientCapabilities {_dynamicRegistration = Just True}), _definition = Just (DefinitionClientCapabilities {_dynamicRegistration = Just True}), _typeDefinition = Just (TypeDefinitionClientCapabilities {_dynamicRegistration = Just True}), _implementation = Just (ImplementationClientCapabilities {_dynamicRegistration = Just True}), _codeAction = Just (CodeActionClientCapabilities {_dynamicRegistration = Just True, _codeActionLiteralSupport = Just (CodeActionLiteralSupport {_codeActionKind = CodeActionKindClientCapabilities {_valueSet = List [CodeActionUnknown "",CodeActionQuickFix,CodeActionRefactor,CodeActionRefactorExtract,CodeActionRefactorInline,CodeActionRefactorRewrite,CodeActionSource,CodeActionSourceOrganizeImports]}})}), _codeLens = Just (CodeLensClientCapabilities {_dynamicRegistration = Just True}), _documentLink = Just (DocumentLinkClientCapabilities {_dynamicRegistration = Just True}), _colorProvider = Just (ColorProviderClientCapabilities {_dynamicRegistration = Just True}), _rename = Just (RenameClientCapabilities {_dynamicRegistration = Just True, _prepareSupport = Just True}), _publishDiagnostics = Just (PublishDiagnosticsClientCapabilities {_relatedInformation = Just True, _tagSupport = Just (PublishDiagnosticsTagsClientCapabilities {_valueSet = List [DtUnnecessary,DtDeprecated]})}), _foldingRange = Just (FoldingRangeClientCapabilities {_dynamicRegistration = Just True, _rangeLimit = Just 5000, _lineFoldingOnly = Just True})}), _window = Just (WindowClientCapabilities {_workDoneProgress = Just True}), _experimental = Nothing}, _trace = Just TraceOff, _workspaceFolders = Just (List [WorkspaceFolder {_uri = "file:///home/francisco/Projects/samples/haskell", _name = "haskell"}])}} GHC installation not found in libdir: /opt/ghc/8.10.1/lib/ghc-8.10.1

@oblitum Hmm that's not good. Does /opt/ghc/8.10.1/lib/ghc-8.10.1 indeed exist and contain files? And what's the output of running ghc --print-libdir?
The library directory should contain files like:

Cabal-3.2.0.0             filepath-1.4.2.1          haskeline-0.8.0.0         package.conf.d            terminfo-0.4.1.4
array-0.5.4.0             ghc-8.10.1                hpc-0.6.1.0               parsec-3.1.14.0           text-1.2.3.2
base-4.14.0.0             ghc-boot-8.10.1           html                      platformConstants         time-1.9.3
bin                       ghc-boot-th-8.10.1        include                   pretty-1.1.3.6            transformers-0.5.6.2
binary-0.8.8.0            ghc-compact-0.1.0.0       integer-gmp-1.0.3.0       process-1.6.8.2           unix-2.7.2.2
bytestring-0.10.10.0      ghc-heap-8.10.1           latex                     rts                       xhtml-3000.2.2.1
containers-0.6.2.1        ghc-prim-0.6.1            libiserv-8.10.1           settings
deepseq-1.4.4.0           ghc-usage.txt             llvm-passes               stm-2.5.0.0
directory-1.3.6.0         ghci-8.10.1               llvm-targets              template-haskell-2.16.0.0
exceptions-0.10.4         ghci-usage.txt            mtl-2.2.2                 template-hsc.h

@bubba no, there's nothing about ghc on /opt/, no idea why it entered the equation now. ghc --print-libdir gives /home/francisco/.ghcup/ghc/8.10.1/lib/ghc-8.10.1, it's the correct path.

@oblitum Ah, I believe that /opt/ghc/8.10.1/lib/ghc-8.10.1 path is the path to GHC on the GitHub Actions linux runner. Which is exactly what we're trying to avoid here. ghc-paths bakes this in to the binary, but I thought I removed all uses of it. Time to investigate

@oblitum Can you try the binaries from https://github.com/bubba/haskell-language-server/releases/tag/test-release-33 now and see if they are any better? ghc-check should now be using the library directory from hie-bios now to do the version check

@bubba it's working great, I tested in my previous ghc-8.10.1 ghcup setup, then completely removed it and just installed ghc-8.8.3. There's no issues with newline char anymore, and it works with either ghc in the system for standalone file edit. The only thing left from what I commented are the line breaks in the log, which is kinda harmless and supposedly almost never touched anyway.

Thanks!

@bubba fyi, I'm pointing people (on coc.nvim wiki at least) to download from the latest release URL, so if you feel confident to mark a newer test-release as latest release instead of pre-release, please do so.

Thanks, forgot to update that. The vscode extension downloads binaries from the latest non-prerelease release on GitHub, so I usually mark it as pre-release whilst the binaries are being updated. Once this is fully merged into master etc. etc would you mind if I pinged you to update the coc.nvim wiki again?

@bubba yeah sure, when this gets into upstream feel free to ping me.

I wholly share @enricopolanski's and @oblitum's experiences, and happily volunteer to beta-test this, too!

I just tried downloading VSIX @bubba posted and installing it in a clean Ubuntu devcontainer. Results:

  • Extension installed 👌
  • haskell-language-server-wrapper downloaded without errors
  • Then two errors showed up:

    1. > haskell-language-server executable missing, please make sure it is installed, see https://github.com/haskell/haskell-language-server.

    2. > Couldn't figure out what GHC version the project is using

Feel free to ping me, too, when something related to this is ready for testing!

@tomasaschan thanks for trying it out! That does indeed sound bad, are you able to share the project/file you were working on? If not then do you know if it's a cabal/stack project and what GHC version it should be using?

I'll see if I can put together a simple repro in a repository!

@bubba Here's a repro repository with some instructions on how to test this yourself: https://github.com/tomasaschan/vscode-hls-repro

The stack config there is hand-written, not generated by stack (I don't have stack available on this machine...) so it might be a little _too_ minimal. If so, feel free to update (and do file a PR with the changes, so I can learn what's required too!).

@bubba Tried with the 0.1.0 VSIX, and got the following errors instead:

haskell-language-server executable missing, please make sure it is installed, see https://github.com/haskell/haskell-language-server.

Couldn't find any pre-built haskell-language-server binaries for Linux and

(yes, the second error message ends in the middle of the sentence like that...)

Not sure what else might be diffing in our configs here, if 0.1.0 is working for you. Do I need to pre-install _anything_ in the environment before this extension?

Not sure whether it's related or not, but in my case where I'm just grabbing the binaries for my OS version, I unpack them on ~/.local/bin and have to strip the OS part ("-Linux") from the uncompressed file (otherwise the wrapper wouldn't find the servers), and set executable bit.

@oblitum Which binaries are you installing that way? Stack? HLS?

I'm installing the VSIX on a machine with clean Ubuntu 20.04 - _nothing_ installed manually. I was under the impression that the point of this ticket was to make that work, i.e. the extension downloads everything I need, but maybe that was a little too much to hope for 😄 Do I need to do more prep work for this extension to work?

@tomasaschan sorry for the late reply, I ended up going down a bit of rabbit hole with your scenario as I wasn't 100% sure exactly how hie-bios was handling stack projects whenever stack wasn't installed on the machine (It was working locally for me but I have all 3 of ghc, cabal and stack installed). I thought it would have fallen back to to just a plain cabal project. Just to confirm do you also have cabal on that machine?

edit: just seeing your reply to Oblitum, unfortunately at the very least for ghc will need to be installed due to how it packages essential core libraries needed for the GHC API, as well as cabal/stack depending on the project, since they are needed to build dependencies and set up the environment. I'm currently updating the readme to clarify this. Admittedly this is a bit of a pain, but I'm hopeful that we might be able to get rid of the ghc dependency at some point by shipping the core libraries alongside the binaries

@tomasaschan I think that error message is bogus by the way, I think haskell-language-server-wrapper --project-ghc-version is still most likely failing. Can you try executing ~/Library/Application\ Support/Code/User/globalStorage/alanz.vscode-hie-server/haskell-language-server-wrapper-test-release-33 --project-ghc-version inside that project directory and see what it returns? Or %APPDATA%\Code\User\globalStorage\alanz.vscode-hie-server/haskell-language-server-wrapper-test-release-33.exe if you're on windows. (I don't know where linux downloads these binaries to yet sorry!)

@oblitum that's a good point. For the case where these binaries are manually installed we need to either figure out how to rename them, or adjust the wrapper to find these tagged binaries. cc @jneira @fendor

@tomasaschan, bubba already answered you well. Regarding that I was just referring to the language server binaries themselves, which comes with OS name in them, and I have to edit that out for them to be usable.

@bubba Figured out how to run the wrapper from within my repro folder. It seems the file name is maybe not what you expected, but also that I'm missing a bunch of dependencies:

$ /root/.vscode-server/data/User/globalStorage/alanz.vscode-hie-server/haskell-language-server-wrapper-test-release-33-linux --project-ghc-version
/root/.vscode-server/data/User/globalStorage/alanz.vscode-hie-server/haskell-language-server-wrapper-test-release-33-linux: error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory

I have a different devcontainer image somewhere with Stack installed; I'll try again with that one and see what happens.

@tomasaschan on ArchLinux I had to install ncurses5-compat-libs for that, it's really a dependency (only one missing for me on a given machine).

Yes! After adding apt-get install libncurses-dev libtinfo5 to the Docker image, it seems to work!

I've updated the repo to use a different base image, which also has stack available, and now I can both install the extension and build the program :D

Not sure everything is working correctly, yet, though: when I hover something, the extension logs say something about "hover request for /path/to/hello.hs:4:2" but no tool tip shows up.

Hover does displays type and docs for me, that should have been the same on your side I guess.

Turns out it was just waiting for a other couple of setup steps - eventually it worked!

One kink though - it seems it has to successfully download all the components or none of them. In one of my attempts the network connection was lost when downloading HLS, and when I restarted the wrapper didn't retry the download. I had to uninstall manually remove the wrapper and reload the window for the download processing to restart properly.

@tomasaschan That is indeed an issue that I would like to fix before shipping this, I'm wondering what the best method is to check if the binary is properly downloaded. Maybe like shasum check? Perhaps GitHub releases provides an api for generating it for us. Or maybe we can generate a shasum file ourselves

  • [x] Check binary is properly downloaded otherwise retry download
  • [x] When downloading binary prevent opening other files from trying to launch the binary that is currently being downloaded

Putting this down here out of interest, here are the dynamically linked libraries that haskell-language-server depends on on macOS:

$ objdump -macho --dylibs-used  haskell-language-server
haskell-language-server:
    /usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
    /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1)
    /usr/lib/libcharset.1.dylib (compatibility version 2.0.0, current version 2.0.0)

As far as I can tell all of these come installed on macOS Catalina. Although the ncurses dependency is making me wonder where on earth it is coming from

This is the list on ArchLinux:

❯ ldd haskell-language-server-wrapper
        linux-vdso.so.1 (0x00007fff185de000)
        libz.so.1 => /usr/lib/libz.so.1 (0x00007faa3a937000)
        libtinfo.so.5 => /usr/lib/libtinfo.so.5 (0x00007faa3a8d2000)
        librt.so.1 => /usr/lib/librt.so.1 (0x00007faa3a8c7000)
        libutil.so.1 => /usr/lib/libutil.so.1 (0x00007faa3a8c2000)
        libdl.so.2 => /usr/lib/libdl.so.2 (0x00007faa3a8bc000)
        libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007faa3a89a000)
        libgmp.so.10 => /usr/lib/libgmp.so.10 (0x00007faa3a7f7000)
        libm.so.6 => /usr/lib/libm.so.6 (0x00007faa3a6b2000)
        libc.so.6 => /usr/lib/libc.so.6 (0x00007faa3a4eb000)
        /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007faa3a9ab000)

The ncurses dependency here is more indirect, it's of a library part of ncurses, libtinfo. ncurses dep struck me with estrangement too, also have no idea from where it comes from, and didn't look further.

It's documented as necessary on README though.

@oblitum after digging through the dependency graph the curses dependency comes from terminfo, which comes from the GHC API itself. There’s definitely a lot more libraries involved in the Linux version it seems like though. However @puffnfresh has a branch that has built properly static binaries with those libraries on alpine Linux, so we could use those! On macOS it’s not possible to have truly static binaries since that libSystem can never be statically linked, but we should check Windows as well anyway to see if there any dlls it depends on

Yeah my branch solves that problem. I'd love to get my work upstream but I deviated quite a bit to get something working well. Will take time.

I'm not sure what your exact plans are, but rustup allows to install the rust-language-server too. I wouldn't mind if installing haskell-language-server becomes part of the scope of ghcup. I guess that's up to debate.

It would be incredible awesome if HLS could be distributed via ghcup! It would be a giant leap towards effortless installation!

@puffnfresh Out of curiosity I just flicked on --enable-executable-static for the linux builds and they seemed to build fine, and a quick ldd revealed there were no dynamic executables linked:

$ ldd haskell-language-server-Linux-8.10.1
ldd haskell-language-server-Linux-8.10.1
    not a dynamic executable

It also seems to run fine after uninstalling ghc, but I need to admit I did this really naïvely. It looks like your branch was doing it from a clean alpine image + custom ghcup? I feel like I'm definitely missing something here, what's the catch?

@hasufell Agreed, that would complete the installation process for other clients outside of vscode. Once this is merged remind me to come back to you on this!

@bubba woo, awesome!!

glibc and gmp are licensed under LGPL. For proprietary software that can be a problem but shouldn't be a problem here.

But statically linking glibc can be tricky. The way NSS works is that it will try to dynamically load different backends (e.g. hosts file, DNS, etc) which it might try to do, depending on your glibc flags:

https://sourceware.org/glibc/wiki/FAQ#Even_statically_linked_programs_need_some_shared_libraries_which_is_not_acceptable_for_me.__What_can_I_do.3F

I'm happy to test this stuff on NixOS which is a good hostile environment for this stuff. Should I grab your latest builds?

I tried the artifacts at https://github.com/bubba/haskell-language-server/releases/tag/test-release-37 and they work great on NixOS!

Awesome work!!

Quick update, the haskell-language-server part has been merged into master, thanks to all for helping test and patch this! Parallel to this the changes to ghcide are also being upstreamed in https://github.com/digital-asset/ghcide/pull/697 https://github.com/digital-asset/ghcide/pull/696 and https://github.com/digital-asset/ghcide/pull/693

The next step is to make a new release here and get some binaries generated, and have people test and try them out with their language clients

I'm happy to report that 0.2.1 is now out with static binaries, and the new VS Code extension will automatically download them for you. Now, to see if we can automatically install these binaries in other clients: https://github.com/emacs-lsp/lsp-mode/issues/506#issuecomment-548455740

https://video.twimg.com/ext_tw_video/1286046540365266944/pu/pl/Ck1W2liTcQkT-xTw.m3u8?tag=10&descending=true

This is great news, really! I warmly thank everyone contributing to HLS, and this issue in particular. This is a huge step forward newcomer integration o/

Nice! I think on coc.nvim side, something could be done in the sense of how many coc extensions works there, for example coc-rust-analyzer (cc @fannheyward) already auto install and updates rust-analyzer binaries as soon as there's new GitHub releases. Soon enough a coc-haskell / coc-hls will show up.

@bubba how does the wrapper looks up for the proper server binaries, does it look in PATH or in the same directory it is in, or both? Asking because in general, other extensions that auto download binaries don't put them in PATH, but that isn't a problem at all because it's just one binary for which you can set a fully qualified command to be executed, but with a wrapper that depends on other bins that can't be done, except for the wrapper itself.

@oblitum that's a relief to hear it's still working!

It doesn't actually "install" them in the sense that it doesn't put anything on the PATH.
The extension first downloads the wrapper to the the globalStorage directory which is somewhere in ~/.config/Code/User on Linux, or ~/Library/Application Support/Code/Users/globalStorage/alanz.vscode-hie-server on mac. (I'm not actually sure what the exact path is on linux, if someone could let me know or fill that in on the vscode plugin readme that would be much appreciated)
It then runs the haskell-language-server-wrapper binary with --project-ghc-version to work out what GHC version the project is using. From there, it then downloads the appropriate GHC version of haskell-language-server into that same globalStorage directory, and then launches it. Or if it's already downloaded, just uses what was previously stored there.
So it's all kept in a sandboxed-ish location, and this also has the benefit in that it only downloads the versions needed, if that makes sense

@bubba OK, I just attempted a manual non-PATH setup and it didn't work. For example, I created some directory and put all the HLS bins there, wrapper and servers. Then I configured coc.nvim language server command to the full path of the wrapper (instead of simple executable name to be resolved from PATH, as usual), it got executed, but it was unable to find the servers that were in the same directory as the wrapper.

I'm not sure how the VSCode extension coupled with the wrapper provisions all that to make it work, so my approach was a more dull/basic one.

(no cabal/stack project involved, just simple haskell file)

@oblitum ah, the wrapper currently only searches for binaries on the PATH at the moment. The VS Code extension doesn't actually launch the server via the wrapper. We'll need to update the README here to clarify this

@bubba I think there's another big opportunity for improving the newbie experience: the first thing that happens after a successful download of the language server binary is that I hover something and see Loading... for _ever_, because it seems it needs to build the world before it can actually show a tooltip. It's probably taking long because I've opened a nontrivial existing project, but that scenario should still be supported IMO. The only way I can see that something is happening is by clicking my way into the extension logs, which I don't expect someone new to the ecosystem to do necessarily (especially if they're new to VS Code, not only to Haskell).

One way to alleviate that, would be to do some dummy action with the HLS after a successful download, during which a progress bar shows up like the one during the download. This shows that there's still some work to do before the extension is fully usable.

@tomasaschan I agree, and I tried to do just that in https://github.com/digital-asset/ghcide/pull/644, which added a "Setting up project foo" spinny progress indicator in the status bar for whenever the project was still building the world etc.
But I think it gets overshadowed by the generic "Progress: 1/2" progress message which is a lot easier to miss and less informative. I'm going to take a quick look at this in ghcide and see if it's something I can fix

Cool! Just tried the latest published version (2.1) and didn't see anything - didn't realize it was already fixed. Will it be available already in 2.2?

The progress message is there in 0.2.1 but it's still getting hijacked by that "Progress: 1/2", you should be seeing something like this: https://streamable.com/nqbcfk . Hopefully there will be a fix for the hijacking in 2.2!

Was this page helpful?
0 / 5 - 0 ratings