Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Lazy load projects #1957

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion release/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,11 @@
"description": "Path to the directory or solution file that should be loaded as a workspace. If set, no workspace probing or discovery is done by Ionide at all.",
"scope": "window",
"type": "string"
},
"FSharp.lazyLoadWorkspace": {
"default": false,
"description": "Configures Ionide to not load any projects upfront but instead load them when .fs files are opened.",
"type": "boolean"
}
},
"title": "F#",
Expand Down Expand Up @@ -1776,4 +1781,4 @@
"url": "https://github.com/ionide/ionide-vscode-fsharp.git"
},
"version": "7.15.2"
}
}
2 changes: 1 addition & 1 deletion src/Components/MSBuild.fs
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ module MSBuild =
let unlessIgnored (path: string) f =
if Project.isIgnored path then unbox () else f path

let initWorkspace _n = Project.initWorkspace ()
let initWorkspace _n = Project.initWorkspace context

let solutionWatcher = workspace.createFileSystemWatcher (U2.Case1 "**/*.sln")

Expand Down
6 changes: 3 additions & 3 deletions src/Components/SolutionExplorer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ module SolutionExplorer =
setParentRef s result
result
| WorkspacePeekFound.Directory dir ->
let items = dir.Fsprojs |> Array.map getProjItem |> List.ofArray
let items = dir.Fsprojs |> Array.map (fun f -> getProjItem f.Path) |> List.ofArray

let result = Workspace items
setParentRefs items result
Expand Down Expand Up @@ -714,7 +714,7 @@ module SolutionExplorer =
| PackageReference _
| ProjectReference _ -> None

let newProject () =
let newProject (context: ExtensionContext) =
promise {
let! templates = LanguageService.dotnetNewList ()

Expand Down Expand Up @@ -777,7 +777,7 @@ module SolutionExplorer =
| _ ->
//If it's the first project in the workspace we need to init the workspace
if Project.getInWorkspace().IsEmpty then
do! Project.initWorkspace ()
do! Project.initWorkspace context

()
| _ -> ()
Expand Down
6 changes: 5 additions & 1 deletion src/Core/DTO.fs
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,16 @@ module DTO =

type WorkspacePeek = { Found: WorkspacePeekFound[] }

and WorkspacePeekFsproj =
{ Path: string; CompileItems: string[] }

and WorkspacePeekFound =
| Directory of WorkspacePeekFoundDirectory
| Solution of WorkspacePeekFoundSolution

and WorkspacePeekFoundDirectory =
{ Directory: string; Fsprojs: string[] }
{ Directory: string
Fsprojs: WorkspacePeekFsproj[] }

and WorkspacePeekFoundSolution =
{ Path: string
Expand Down
45 changes: 33 additions & 12 deletions src/Core/Project.fs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ module Project =

let deepLevel = "FSharp.workspaceModePeekDeepLevel" |> Configuration.get 2 |> max 0

let lazyLoadWorkspace = "FSharp.lazyLoadWorkspace" |> Configuration.get false

let isNetCoreApp (project: Project) =
project.Info.TargetFramework :: project.Info.TargetFrameworks
|> Seq.exists (fun tfm -> tfm = "net5.0" || tfm.StartsWith "netcoreapp")
Expand Down Expand Up @@ -106,8 +108,7 @@ module Project =
| Folder folder -> folder.Items |> Array.collect getProjs

sln.Items |> Array.collect getProjs |> Array.toList
| Some(WorkspacePeekFound.Directory dir) -> dir.Fsprojs |> Array.toList

| Some(WorkspacePeekFound.Directory dir) -> dir.Fsprojs |> Array.map (fun f -> f.Path) |> Array.toList

let getNotLoaded () =
let lst =
Expand Down Expand Up @@ -250,7 +251,7 @@ module Project =
let projs =
match loadedWorkspace with
| None -> Array.empty
| Some(WorkspacePeekFound.Directory dir) -> dir.Fsprojs
| Some(WorkspacePeekFound.Directory dir) -> dir.Fsprojs |> Array.map (fun f -> f.Path)
| Some(WorkspacePeekFound.Solution sln) -> sln.Items |> Array.collect foldFsproj |> Array.map fst

let loadingInProgress p =
Expand Down Expand Up @@ -545,7 +546,7 @@ module Project =

let wdir =
{ WorkspacePeekFoundDirectory.Directory = workspace.rootPath.Value
Fsprojs = fsprojs |> Array.ofList }
Fsprojs = fsprojs |> List.map (fun p -> { Path = p; CompileItems = [||] }) |> Array.ofList }

return WorkspacePeekFound.Directory wdir
}
Expand Down Expand Up @@ -642,30 +643,50 @@ module Project =
setAnyProjectContext true
| None -> ()

let private initWorkspaceHelper x =
let private initWorkspaceHelper (context: ExtensionContext) x =
clearLoadedProjects ()
loadedWorkspace <- Some x
workspaceChangedEmitter.fire x

let projs =
match x with
| WorkspacePeekFound.Directory dir -> dir.Fsprojs
| WorkspacePeekFound.Solution sln -> sln.Items |> Array.collect foldFsproj |> Array.map fst
| WorkspacePeekFound.Directory dir -> dir.Fsprojs |> Array.map (fun f -> (f.Path, f.CompileItems))
| WorkspacePeekFound.Solution sln -> sln.Items |> Array.collect foldFsproj |> Array.map (fun (p, _) -> (p, [||]))

match x with
| WorkspacePeekFound.Solution _ -> setAnyProjectContext true
| WorkspacePeekFound.Directory _ when not (projs |> Array.isEmpty) -> setAnyProjectContext true
| _ -> ()

projs |> List.ofArray |> LanguageService.workspaceLoad |> Promise.map ignore
if lazyLoadWorkspace then
//TODO: Register a file open event handler and load the project on demand
let fsFileToProj = Dictionary<string, string>()
for (proj, compileItems) in projs do
for compileItem in compileItems do
fsFileToProj.[compileItem] <- proj

let openFileHandler (e: TextDocument) =

match tryFindInWorkspace e.uri.path with
| Some(ProjectLoadingState.Loaded _) -> ()
| Some(ProjectLoadingState.Loading _) -> ()
| _ -> LanguageService.workspaceLoad [ fsFileToProj[e.uri.path] ] |> ignore

// workspace.onDidOpenTextDocument $ (openFileHandler, (), context.subscriptions) |> ignore
workspace.onDidOpenTextDocument.Invoke(unbox openFileHandler)
|> context.Subscribe

Promise.lift ()
else
projs |> Array.map(fun (p, _) -> p) |> List.ofArray |> LanguageService.workspaceLoad |> Promise.map ignore


let initWorkspace () =
let initWorkspace (context: ExtensionContext) =
getWorkspace ()
|> Promise.bind (function
| Some x -> Promise.lift x
| None -> getWorkspaceForModeIonideSearch ())
|> Promise.bind (initWorkspaceHelper)
|> Promise.bind (initWorkspaceHelper context)

module internal ProjectStatus =
let mutable timer = None
Expand Down Expand Up @@ -744,7 +765,7 @@ module Project =
workspacePeek ()
|> Promise.bind (fun x -> pickFSACWorkspace x (CurrentWorkspaceConfiguration.get ()))
|> Promise.bind (function
| Some w -> initWorkspaceHelper w
| Some w -> initWorkspaceHelper context w
| None -> Promise.empty)
|> box
|> Some)
Expand All @@ -760,4 +781,4 @@ module Project =
)
|> context.Subscribe

initWorkspace ()
initWorkspace context
2 changes: 1 addition & 1 deletion src/fsharp.fs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ let private activateLanguageServiceRestart (context: ExtensionContext) =
logger.Debug("Restarting F# language service")
do! LanguageService.stop ()
do! LanguageService.start context
do! Project.initWorkspace ()
do! Project.initWorkspace context
}

commands.registerCommand ("fsharp.restartLanguageService", restart |> objfy2)
Expand Down