dotnet / fsharp

The F# compiler, F# core library, F# language service, and F# tooling integration for Visual Studio
https://dotnet.microsoft.com/languages/fsharp
MIT License
3.88k stars 783 forks source link

LSP: Mechanism for keeping workspace/solution state #16641

Open 0101 opened 8 months ago

0101 commented 8 months ago

Use ProjectQuery API to construct initial state + subscribe for updates. Use incoming documentOpen / Closed / Changed notifications to keep track of solution state. Try to build this on top of FSharpProjectSnapshot.

nojaf commented 6 months ago

Hi,

Yesterday, @0101, @auduchinok, and I had a chat about bringing the Transparent Compiler into Rider. We focused on how the new ProjectSnapshot setup changes the way we keep track of everything.

Here's the deal: When we make a ProjectSnapshot, each file gets a timestamp or version. This helps the system remember things, and when a file gets updated, it needs a fresh version in the snapshot. Updating a file means making a new FileSnapshot and using the .Replace function to refresh the snapshot.

This is okay but gets complicated when we talk about projects that depend on each other. Because snapshots include the projects they depend on, if you change one file, you theoretically need to update everything. Imagine having 300 projects; typing in one file would mean all those snapshots need an update every time you press a key.

From what I understand, Visual Studio doesn't rush to update everything right away when a file changes. It waits until the snapshot is needed for something before it updates it.

Our plan for now is to have a system on Rider's side that makes ProjectSnapshots from ProjectOptions. When a file changes, this system would get rid of the outdated snapshots, which helps us avoid making too many new ones. This might be a good first step for using the Transparent Compiler with Rider, but it seems like something all IDEs will have to figure out.

This is where the idea of a new Workspace comes in. It would be awesome if we could use this setup to ask for snapshots since the FSharpChecker should always work with snapshots. So, if I need type check info for a file, I could ask the Workspace for the snapshot using the project key (project name + TFM), get the snapshot, use FSharpChecker, and get my answers. And when a file changes, I just tell the Workspace. It would handle whatever needs to be done.

sequenceDiagram
    participant IDE as IDE
    participant Workspace as Workspace
    participant FSharpChecker as FSharpChecker

    IDE->>Workspace: Request ProjectSnapshot (project key)
    Workspace-->>IDE: ProjectSnapshot
    IDE->>FSharpChecker: Get information (ProjectSnapshot)
    FSharpChecker-->>IDE: Information results

    IDE->>Workspace: File changed
    IDE->>Workspace: Project options changed
    IDE->>Workspace: Assembly changed

This seems like a smart way to manage snapshots across different editors. The Workspace shouldn't be tied down to LSP; it should work with everything or be easy to plug into. Each editor (VS, Ionide, and Rider) could throw in their two cents on what they need from the Workspace, and we could build something that works for everyone.

@0101 had a cool idea yesterday about trying something called adaptive programming inside the Workspace. This could make handling changes across projects smoother. The thought is that the Workspace could know about file changes from the editor and only update things in a project when someone asks for that project's snapshot. It's just an idea, and I'm not sure if it's possible, but it's worth thinking about.

(//cc @theangrybyrd & @baronfel for FSAC input)

vzarytovskii commented 6 months ago

Yeah, that was the general idea - abstract it away so it's easy to work with it in some abstract editor/IDE.