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] Using MiscellaneousFilesWorkspace to handle single files #5733

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
<Compile Include="LanguageService\FSharpCheckerProvider.fs" />
<Compile Include="LanguageService\FSharpProjectOptionsManager.fs" />
<Compile Include="LanguageService\LegacyProjectWorkspaceMap.fs" />
<Compile Include="LanguageService\SingleFileWorkspaceMap.fs" />
<Compile Include="LanguageService\LanguageService.fs" />
<Compile Include="LanguageService\AssemblyContentProvider.fs" />
<Compile Include="LanguageService\SymbolHelpers.fs" />
Expand Down
51 changes: 8 additions & 43 deletions vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs
Original file line number Diff line number Diff line change
Expand Up @@ -175,60 +175,25 @@ type internal FSharpLanguageService(package : FSharpPackage, solution: IVsSoluti

let projectInfoManager = package.ComponentModel.DefaultExportProvider.GetExport<FSharpProjectOptionsManager>().Value

let projectDisplayNameOf projectFileName =
if String.IsNullOrWhiteSpace projectFileName then projectFileName
else Path.GetFileNameWithoutExtension projectFileName

let singleFileProjects = ConcurrentDictionary<_, IWorkspaceProjectContext>()

let tryRemoveSingleFileProject projectId =
match singleFileProjects.TryRemove(projectId) with
| true, project ->
projectInfoManager.ClearInfoForSingleFileProject(projectId)
project.Dispose()
| _ -> ()

let tryGetOrCreateProjectId (workspace: VisualStudioWorkspaceImpl) (projectFileName: string) =
let projectDisplayName = projectDisplayNameOf projectFileName
Some (workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName))

let mutable legacyProjectWorkspaceMap = Unchecked.defaultof<LegacyProjectWorkspaceMap>
let mutable singleFileWorkspaceMap = Unchecked.defaultof<SingleFileWorkspaceMap>

override this.Initialize() =
base.Initialize()

this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Completion.CompletionOptions.BlockForCompletionItems, FSharpConstants.FSharpLanguageName, false)
this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Shared.Options.ServiceFeatureOnOffOptions.ClosedFileDiagnostic, FSharpConstants.FSharpLanguageName, Nullable false)

this.Workspace.DocumentClosed.Add <| fun args -> tryRemoveSingleFileProject args.Document.Project.Id

legacyProjectWorkspaceMap <- LegacyProjectWorkspaceMap(this.Workspace, solution, projectInfoManager, package.ComponentModel.GetService<IWorkspaceProjectContextFactory>(), this.SystemServiceProvider)
let projectContextFactory = package.ComponentModel.GetService<IWorkspaceProjectContextFactory>()
legacyProjectWorkspaceMap <- LegacyProjectWorkspaceMap(this.Workspace, solution, projectInfoManager, projectContextFactory, this.SystemServiceProvider)
legacyProjectWorkspaceMap.Initialize()

singleFileWorkspaceMap <- SingleFileWorkspaceMap(this.Workspace, projectInfoManager, projectContextFactory)
singleFileWorkspaceMap.Initialize()

let theme = package.ComponentModel.DefaultExportProvider.GetExport<ISetThemeColors>().Value
theme.SetColors()

member this.SetupStandAloneFile(fileName: string, fileContents: string, workspace: VisualStudioWorkspaceImpl, hier: IVsHierarchy) =
let loadTime = DateTime.Now
let projectFileName = fileName
let projectDisplayName = projectDisplayNameOf projectFileName

let mutable projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName)

if isNull (workspace.ProjectTracker.GetProject projectId) then
let projectContextFactory = package.ComponentModel.GetService<IWorkspaceProjectContextFactory>();

let projectContext = projectContextFactory.CreateProjectContext(FSharpConstants.FSharpLanguageName, projectDisplayName, projectFileName, projectId.Id, hier, null)

projectId <- workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName)

projectContext.AddSourceFile(fileName)

singleFileProjects.[projectId] <- projectContext

let _referencedProjectFileNames, parsingOptions, projectOptions = projectInfoManager.ComputeSingleFileOptions (tryGetOrCreateProjectId workspace, fileName, loadTime, fileContents) |> Async.RunSynchronously
projectInfoManager.AddOrUpdateSingleFileProject(projectId, (loadTime, parsingOptions, projectOptions))

override this.ContentTypeName = FSharpConstants.FSharpContentTypeName
override this.LanguageName = FSharpConstants.FSharpLanguageName
override this.RoslynLanguageName = FSharpConstants.FSharpLanguageName
Expand Down Expand Up @@ -279,14 +244,14 @@ type internal FSharpLanguageService(package : FSharpPackage, solution: IVsSoluti
// This is the path when opening out-of-project .fs/.fsi files in CPS projects

let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter)
this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier)
singleFileWorkspaceMap.AddFile(filename, fileContents, hier)
| _ -> ()
| _ ->

// This is the path for both in-project and out-of-project .fsx files

let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter)
this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier)
singleFileWorkspaceMap.AddFile(filename, fileContents, hier)

| _ -> ()
| _ -> ()
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace Microsoft.VisualStudio.FSharp.Editor

#nowarn "40"

open System
open System.Collections.Concurrent
open System.Collections.Generic
open System.Diagnostics
open System.IO
open System.Linq
open System.Runtime.CompilerServices
open Microsoft.CodeAnalysis
open Microsoft.VisualStudio
open Microsoft.VisualStudio.FSharp.Editor
open Microsoft.VisualStudio.FSharp.Editor.SiteProvider
open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
open Microsoft.VisualStudio.LanguageServices.ProjectSystem
open Microsoft.VisualStudio.Shell.Interop

[<Sealed>]
type internal SingleFileWorkspaceMap(workspace: VisualStudioWorkspaceImpl,
projectInfoManager: FSharpProjectOptionsManager,
projectContextFactory: IWorkspaceProjectContextFactory) =

let mutable isInitialized = false
let singleFileProjects = ConcurrentDictionary<_, IWorkspaceProjectContext>()

let tryRemoveSingleFileProject projectId =
match singleFileProjects.TryRemove(projectId) with
| true, project ->
projectInfoManager.ClearInfoForSingleFileProject(projectId)
project.Dispose()
| _ -> ()

let projectDisplayNameOf projectFileName =
if String.IsNullOrWhiteSpace projectFileName then projectFileName
else Path.GetFileNameWithoutExtension projectFileName

let tryGetOrCreateProjectId (workspace: VisualStudioWorkspaceImpl) (projectFileName: string) =
let projectDisplayName = projectDisplayNameOf projectFileName
Some (workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName))

member this.Initialize() =
if not isInitialized then
workspace.DocumentClosed.Add <| fun args -> tryRemoveSingleFileProject args.Document.Project.Id
isInitialized <- true

member this.AddFile(fileName: string, fileContents: string, hier: IVsHierarchy) =
if not isInitialized then
failwith "SingleFileWorkspaceMap is not initialized."

let loadTime = DateTime.Now
let projectFileName = fileName
let projectDisplayName = projectDisplayNameOf projectFileName

let mutable projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName)

if isNull (workspace.ProjectTracker.GetProject projectId) then
let projectContext = projectContextFactory.CreateProjectContext(FSharpConstants.FSharpLanguageName, projectDisplayName, projectFileName, projectId.Id, hier, null)

projectId <- workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName)

projectContext.AddSourceFile(fileName)

singleFileProjects.[projectId] <- projectContext

let _referencedProjectFileNames, parsingOptions, projectOptions = projectInfoManager.ComputeSingleFileOptions (tryGetOrCreateProjectId workspace, fileName, loadTime, fileContents) |> Async.RunSynchronously
projectInfoManager.AddOrUpdateSingleFileProject(projectId, (loadTime, parsingOptions, projectOptions))