F# language server

I want to share something I’ve been working on for a while: a language-server-protocol implementation for F# https://marketplace.visualstudio.com/items?itemName=georgewfraser.fsharp-language-server

For those who don’t know it, the language server protocol is a standard JSON-RPC mechanism for editors to talk to code-intelligence implementations. It originated with VSCode, but is now supported by Vim, Emacs, and many others. The LSP is pretty similar to the F# Compiler Service API, so my implementation is essentially a shim between the two protocols. My major goal was high-performance, and its been working great for me, even on large projects.

If you’re a VSCode user, please give it a try and raise issues if you have trouble! If you’re a Vim or Emacs user, I would really appreciate it if someone would write instructions for how to install it in these editors and raise a PR.

6 Likes

Hi George. This looks interesting! Unfortunately I’ve run into a problem when installing it: on opening a folder with some projects in it, I get the following error:

Listening on stdin
Add workspace root c:\Users\Isaac\Source\Repos\SAFE-Dojo
Creating project options for script build.fsx
Exception in language server System.Exception: Failed to load PseudoScript.fsproj: The path c:\Users\georgefraser\Documents\fsharp-language-server\client\PseudoScript.fsproj could not be found.

Any ideas how to fix this?

Whoops, an absolute path snuck in there! Just published a fix, please update.

1 Like

That is so cool! It will be real helpful in learning F#.
Thank you

Now I get this:

Listening on stdin
Add workspace root c:\Users\Isaac\Source\Repos\tachyus
Creating project options for script foobar.fsx
Looking for PsuedoScript.fsproj relative to C:\Users\Isaac\.vscode\extensions\georgewfraser.fsharp-language-server-0.1.3\src\FSharpLanguageServer\bin\Release\netcoreapp2.0\win10-x64\publish\ProjectCracker.dll
Cancelling request 1
Build started 04/06/2018 23:26:12.
__________________________________________________
Project "C:\Users\Isaac\.vscode\extensions\georgewfraser.fsharp-language-server-0.1.3\client\PseudoScript.fsproj" (Compile target(s)):

Target GenerateTargetFrameworkMonikerAttribute:
  Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the input files.
Target GetAssemblyVersion:
    C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018: The "GetAssemblyVersion" task failed unexpectedly.
    C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018: System.IO.FileNotFoundException: Could not load file or assembly 'NuGet.Versioning, Version=4.7.0.5, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified.
    C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018: File name: 'NuGet.Versioning, Version=4.7.0.5, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
    C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018:    at Microsoft.NET.Build.Tasks.GetAssemblyVersion.ExecuteCore()
    C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018:    at Microsoft.NET.Build.Tasks.TaskBase.Execute()
    C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018:    at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute() in E:\A\_work\82\s\src\Build\BackEnd\TaskExecutionHost\TaskExecutionHost.cs:line 631
    C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018:    at Microsoft.Build.BackEnd.TaskBuilder.<ExecuteInstantiatedTask>d__25.MoveNext() in E:\A\_work\82\s\src\Build\BackEnd\Components\RequestBuilder\TaskBuilder.cs:line 787
    C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018: 
    C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018: 
Done building target "GetAssemblyVersion" in project "PseudoScript.fsproj" -- FAILED.

Done building project "PseudoScript.fsproj" -- FAILED.

Build FAILED.

C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018: The "GetAssemblyVersion" task failed unexpectedly.
C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018: System.IO.FileNotFoundException: Could not load file or assembly 'NuGet.Versioning, Version=4.7.0.5, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified.
C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018: File name: 'NuGet.Versioning, Version=4.7.0.5, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018:    at Microsoft.NET.Build.Tasks.GetAssemblyVersion.ExecuteCore()
C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018:    at Microsoft.NET.Build.Tasks.TaskBase.Execute()
C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018:    at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute() in E:\A\_work\82\s\src\Build\BackEnd\TaskExecutionHost\TaskExecutionHost.cs:line 631
C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018:    at Microsoft.Build.BackEnd.TaskBuilder.<ExecuteInstantiatedTask>d__25.MoveNext() in E:\A\_work\82\s\src\Build\BackEnd\Components\RequestBuilder\TaskBuilder.cs:line 787
C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018: 
C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets(161,5): error MSB4018: 
    0 Warning(s)
    1 Error(s)

Time Elapsed 00:00:00.49
Exception in language server System.Exception: Failed to load PseudoScript.fsproj: Object reference not set to an instance of an object.
   at ProjectCracker.scriptBase@72.Invoke(Unit unitVar) in /Users/georgefraser/Documents/fsharp-language-server/src/ProjectCracker/ProjectCracker.fs:line 81
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at FSharpLanguageServer.ProjectManager.analyzeFsx(FileInfo fsx) in /Users/georgefraser/Documents/fsharp-language-server/src/FSharpLanguageServer/ProjectManager.fs:line 100
   at FSharpLanguageServer.ProjectManager.ensureAll(FSharpList`1 fs) in /Users/georgefraser/Documents/fsharp-language-server/src/FSharpLanguageServer/ProjectManager.fs:line 178
   at <StartupCode$FSharpLanguageServer>.$ProjectManager.AddWorkspaceRoot@186.Invoke(Unit unitVar) in /Users/georgefraser/Documents/fsharp-language-server/src/FSharpLanguageServer/ProjectManager.fs:line 189
   at Microsoft.FSharp.Control.AsyncBuilderImpl.callA@522.Invoke(AsyncParams`1 args)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.FSharp.Control.AsyncBuilderImpl.commit[a](AsyncImplResult`1 res)
   at Microsoft.FSharp.Control.CancellationTokenOps.RunSynchronouslyInCurrentThread[a](CancellationToken token, FSharpAsync`1 computation)
   at Microsoft.FSharp.Control.CancellationTokenOps.RunSynchronously[a](CancellationToken token, FSharpAsync`1 computation, FSharpOption`1 timeout)
   at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken)
   at LSP.LanguageServer.connect(FSharpFunc`2 serverFactory, BinaryReader receive, BinaryWriter send) in /Users/georgefraser/Documents/fsharp-language-server/src/LSP/LanguageServer.fs:line 213
   at FSharpLanguageServer.Program.main(String[] argv) in /Users/georgefraser/Documents/fsharp-language-server/src/FSharpLanguageServer/Program.fs:line 703
Cancelling request 2
Cancelling request 3
Cancelling request 5
Cancelling request 6
Cancelling request 7

Thanks for sticking with it @isaacabraham, there’s definitely some issues right now reliably analyzing project files. There’s a github issue here where @chethusk and I are working on figuring out a strategy that will “just work”, stay tuned.

Perfect, I’ll follow that repo instead of pasting issues here :slight_smile:

@georgewfraser Is this F# Language Server compatible with Ionide? Or do we need to choose to install one or the other extension in VS Code? Also, a comparison of the features of the two extensions might be helpful (unless I’m completely confused).

EDIT: By the way, I just found the " How is this project different than Ionide?" section in the docs, but I don’t think it answered my questions at all.