diff --git a/src/FSharpSource.BuildFromSource.targets b/src/FSharpSource.BuildFromSource.targets index f5f52bfc790b05adbf78e84d89488ee6ee718257..aff873c491207779a543098a57b2173a2e0afa2d 100644 --- a/src/FSharpSource.BuildFromSource.targets +++ b/src/FSharpSource.BuildFromSource.targets @@ -38,7 +38,8 @@ + Outputs="@(CopyAndSubstituteText->'$(OutDir)%(TargetFilename)')" + Condition="'$(DesignTimeBuild)' != 'true'"> diff --git a/src/buildfromsource.cmd b/src/buildfromsource.cmd index 9d50b36d784a1a75a6a7d746ec679b92a2b58bc7..03d44c5b56827402d7a366fefc9d7eb1fa6f4045 100644 --- a/src/buildfromsource.cmd +++ b/src/buildfromsource.cmd @@ -20,7 +20,7 @@ if ERRORLEVEL 1 echo Error: failed && goto :failure rem build and pack tools dotnet restore %__scriptpath%fsharp\FSharp.Compiler.nuget\FSharp.Compiler.nuget.BuildFromSource.fsproj if ERRORLEVEL 1 echo Error: failed && goto :failure -dotnet pack %__scriptpath%fsharp\FSharp.Compiler.nuget\FSharp.Compiler.nuget.BuildFromSource.fsproj -c release +dotnet pack %__scriptpath%fsharp\FSharp.Compiler.nuget\FSharp.Compiler.nuget.BuildFromSource.fsproj -c debug if ERRORLEVEL 1 echo Error: failed && goto :failure goto :success diff --git a/src/fsharp/FSharp.Build/InternalsVisibleTo.fs b/src/fsharp/FSharp.Build/InternalsVisibleTo.fs index 8543680d83571eaa41d30f6d8082ba2e84df7a0a..d4b4322e15261eab49b089f9122db9e5c88c0a06 100644 --- a/src/fsharp/FSharp.Build/InternalsVisibleTo.fs +++ b/src/fsharp/FSharp.Build/InternalsVisibleTo.fs @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. namespace Microsoft.FSharp -open System.Reflection -[] - +[] do() - diff --git a/src/fsharp/FSharp.Core/FSharp.Core.BuildFromSource.fsproj b/src/fsharp/FSharp.Core/FSharp.Core.BuildFromSource.fsproj index 568a78ef0990fbab4a411a353296ce75e037a274..95a321075141cf7f6520739d2b67cec0b307568a 100644 --- a/src/fsharp/FSharp.Core/FSharp.Core.BuildFromSource.fsproj +++ b/src/fsharp/FSharp.Core/FSharp.Core.BuildFromSource.fsproj @@ -13,7 +13,7 @@ $(OtherFlags) --warnon:1182 --compiling-fslib --compiling-fslib-40 --maxerrors:20 --extraoptimizationloops:1 - + FSCore.resx @@ -212,7 +212,7 @@ - + diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index dd2714b6b7aac3410ad9a37aec0d8be68c661eb8..b9331351ffedd9ff9ad03ef4fee93d9de90d8a4a 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -2468,7 +2468,6 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i do tcConfigB.resolutionEnvironment <- ResolutionEnvironment.EditingOrCompilation false do tcConfigB.useSimpleResolution <- true do SetTargetProfile tcConfigB "netcore" // always assume System.Runtime codegen - //do SetTargetProfile tcConfigB "privatecorelib" // always assume System.Private.CoreLib codegen #endif // Preset: --optimize+ -g --tailcalls+ (see 4505) diff --git a/src/fsharp/vs/IncrementalBuild.fs b/src/fsharp/vs/IncrementalBuild.fs index 8764878737fc3f4fbdec1de3b632a0eed1b3dab2..f940a554be1b451ff36d4955693eed720405e703 100755 --- a/src/fsharp/vs/IncrementalBuild.fs +++ b/src/fsharp/vs/IncrementalBuild.fs @@ -1681,8 +1681,11 @@ type IncrementalBuilder(tcGlobals,frameworkTcImports, nonFrameworkAssemblyInputs /// CreateIncrementalBuilder (for background type checking). Note that fsc.fs also /// creates an incremental builder used by the command line compiler. static member TryCreateBackgroundBuilderForProjectOptions (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, frameworkTcImportsCache: FrameworkImportsCache, loadClosureOpt:LoadClosure option, sourceFiles:string list, commandLineArgs:string list, projectReferences, projectDirectory, useScriptResolutionRules, keepAssemblyContents, keepAllBackgroundResolutions, maxTimeShareMilliseconds) = + let targetProfileSwitch = "--targetprofile:" + let useSimpleResolutionSwitch = "--simpleresolution" + cancellable { - + // Trap and report warnings and errors from creation. use errorScope = new ErrorScope() let! builderOpt = @@ -1695,23 +1698,38 @@ type IncrementalBuilder(tcGlobals,frameworkTcImports, nonFrameworkAssemblyInputs /// Create a type-check configuration let tcConfigB, sourceFilesNew = - + + let getSwitchValue switchstring = + match commandLineArgs |> Seq.tryFindIndex(fun s -> s.StartsWith(switchstring)) with + | Some idx -> Some(commandLineArgs.[idx].Substring(switchstring.Length)) + | _ -> None + // see also fsc.fs:runFromCommandLineToImportingAssemblies(), as there are many similarities to where the PS creates a tcConfigB let tcConfigB = TcConfigBuilder.CreateNew(legacyReferenceResolver, defaultFSharpBinariesDir, implicitIncludeDir=projectDirectory, optimizeForMemory=true, isInteractive=false, isInvalidationSupported=true, defaultCopyFSharpCore=false) + // The following uses more memory but means we don't take read-exclusions on the DLLs we reference // Could detect well-known assemblies--ie System.dll--and open them with read-locks tcConfigB.openBinariesInMemory <- true tcConfigB.resolutionEnvironment <- (ReferenceResolver.ResolutionEnvironment.EditingOrCompilation true) - + tcConfigB.conditionalCompilationDefines <- let define = if useScriptResolutionRules then "INTERACTIVE" else "COMPILED" define::tcConfigB.conditionalCompilationDefines tcConfigB.projectReferences <- projectReferences + #if COMPILER_SERVICE_ASSUMES_DOTNETCORE_COMPILATION tcConfigB.useSimpleResolution <- true // turn off msbuild resolution +#else + tcConfigB.useSimpleResolution <- (getSwitchValue useSimpleResolutionSwitch) |> Option.isSome #endif + match (getSwitchValue targetProfileSwitch) with + | Some v -> + let _s = v + CompileOptions.SetTargetProfile tcConfigB v + | None -> () + // Apply command-line arguments and collect more source files if they are in the arguments let sourceFilesNew = try @@ -1725,12 +1743,16 @@ type IncrementalBuilder(tcGlobals,frameworkTcImports, nonFrameworkAssemblyInputs // Never open PDB files for the language service, even if --standalone is specified tcConfigB.openDebugInformationForLaterStaticLinking <- false - + match commandLineArgs |> Seq.tryFind(fun s -> s.StartsWith(targetProfileSwitch)) with + | Some arg -> + let profile = arg.Substring(targetProfileSwitch.Length) + CompileOptions.SetTargetProfile tcConfigB profile + | _ -> () tcConfigB, sourceFilesNew match loadClosureOpt with - | Some loadClosure -> - let dllReferences = + | Some loadClosure -> + let dllReferences = [for reference in tcConfigB.referencedDLLs do // If there's (one or more) resolutions of closure references then yield them all match loadClosure.References |> List.tryFind (fun (resolved,_)->resolved=reference.Text) with diff --git a/src/fsharp/vs/service.fs b/src/fsharp/vs/service.fs index ea92c92f9ae2e085d42faa1990606f646efdd831..f8e1dac2df8993005f4932e2444ad4430d2618b5 100644 --- a/src/fsharp/vs/service.fs +++ b/src/fsharp/vs/service.fs @@ -3139,7 +3139,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, reactorOps: IReactorOperatio let loadClosure = LoadClosure.ComputeClosureOfSourceText(ctok, legacyReferenceResolver, defaultFSharpBinariesDir, filename, source, CodeContext.Editing, tcConfig.useSimpleResolution, tcConfig.useFsiAuxLib, new Lexhelp.LexResourceManager(), applyCompilerOptions, assumeDotNetFramework) let! tcErrors, tcFileResult = Parser.CheckOneFile(parseResults, source, filename, "project", tcConfig, tcGlobals, tcImports, tcState, Some loadClosure, backgroundDiagnostics, reactorOps, (fun () -> true), None, userOpName) - + return match tcFileResult with | Parser.TypeCheckAborted.No scope -> @@ -3150,7 +3150,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, reactorOps: IReactorOperatio | _ -> failwith "unexpected aborted" } - + //---------------------------------------------------------------------------- // CompilerEnvironment, DebuggerEnvironment // diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index cd4281e4ab693016a4e970e4c42933dc4e854a98..0b2d64bccb98021d2f5704fecfb7f9b075b5c5ff 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -1,20 +1,24 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. -namespace Microsoft.VisualStudio.FSharp.Editor +namespace rec Microsoft.VisualStudio.FSharp.Editor #nowarn "40" open System open System.Collections.Concurrent open System.Collections.Generic +open System.Collections.Immutable open System.ComponentModel.Composition +open System.Diagnostics +open System.IO +open System.Linq open System.Runtime.CompilerServices open System.Runtime.InteropServices -open System.IO -open System.Diagnostics +open System.Threading open Microsoft.FSharp.Compiler.CompileOps open Microsoft.FSharp.Compiler.SourceCodeServices +open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Diagnostics @@ -23,6 +27,7 @@ open Microsoft.CodeAnalysis.Options open Microsoft.VisualStudio open Microsoft.VisualStudio.Editor open Microsoft.VisualStudio.TextManager.Interop +open Microsoft.VisualStudio.LanguageServices open Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem open Microsoft.VisualStudio.LanguageServices.Implementation.TaskList @@ -78,7 +83,6 @@ type internal FSharpCheckerProvider member this.Checker = checker.Value - /// A value and a function to recompute/refresh the value. The function is passed a flag indicating if a refresh is happening. type Refreshable<'T> = 'T * (bool -> 'T) @@ -87,22 +91,33 @@ type Refreshable<'T> = 'T * (bool -> 'T) // This service allows analyzers to get an appropriate FSharpProjectOptions value for a project or single file. // It also allows a 'cheaper' route to get the project options relevant to parsing (e.g. the #define values). // The main entrypoints are TryGetOptionsForDocumentOrProject and TryGetOptionsForEditingDocumentOrProject. - - [); Composition.Shared>] type internal FSharpProjectOptionsManager [] ( checkerProvider: FSharpCheckerProvider, + [)>] workspace: VisualStudioWorkspaceImpl, [)>] serviceProvider: System.IServiceProvider ) = - // A table of information about projects, excluding single-file projects. + + // A table of information about projects, excluding single-file projects. let projectTable = ConcurrentDictionary>() // A table of information about single-file projects. Currently we only need the load time of each such file, plus // the original options for editing let singleFileProjectTable = ConcurrentDictionary() + // Accumulate sources and references for each project file + let projectInfo = new ConcurrentDictionary() + + let projectDisplayNameOf projectFileName = + if String.IsNullOrWhiteSpace projectFileName then projectFileName + else Path.GetFileNameWithoutExtension projectFileName + + let tryGetOrCreateProjectId (projectFileName: string) = + let projectDisplayName = projectDisplayNameOf projectFileName + Some (workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName)) + /// Clear a project from the project table member this.ClearInfoForProject(projectId: ProjectId) = projectTable.TryRemove(projectId) |> ignore @@ -124,7 +139,7 @@ type internal FSharpProjectOptionsManager member this.AddOrUpdateSingleFileProject(projectId, data) = singleFileProjectTable.[projectId] <- data - + /// Get the exact options for a single-file script member this.ComputeSingleFileOptions (tryGetOrCreateProjectId, fileName, loadTime, fileContents, workspace: Workspace) = async { let extraProjectInfo = Some(box workspace) @@ -145,7 +160,7 @@ type internal FSharpProjectOptionsManager } /// Update the info for a project in the project table - member this.UpdateProjectInfo(tryGetOrCreateProjectId, projectId: ProjectId, site: IProjectSite, workspace: Workspace, userOpName) = + member this.UpdateProjectInfo(tryGetOrCreateProjectId, projectId: ProjectId, site: IProjectSite, userOpName) = this.AddOrUpdateProject(projectId, (fun isRefresh -> let extraProjectInfo = Some(box workspace) let tryGetOptionsForReferencedProject f = f |> tryGetOrCreateProjectId |> Option.bind this.TryGetOptionsForProject @@ -153,7 +168,7 @@ type internal FSharpProjectOptionsManager let referencedProjectIds = referencedProjects |> Array.choose tryGetOrCreateProjectId checkerProvider.Checker.InvalidateConfiguration(options, startBackgroundCompileIfAlreadySeen = not isRefresh, userOpName= userOpName + ".UpdateProjectInfo") referencedProjectIds, options)) - + /// Get compilation defines relevant for syntax processing. /// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project /// options for a script. @@ -204,6 +219,84 @@ type internal FSharpProjectOptionsManager | true, (_loadTime, originalOptions) -> Some originalOptions | _ -> this.TryGetOptionsForProject(projectId) + member this.ProvideProjectSiteProvider(project:Project) = + let hier = workspace.GetHierarchy(project.Id) + + {new IProvideProjectSite with + member iProvideProjectSite.GetProjectSite() = + let fst (a, _, _) = a + let thrd (_, _, c) = c + let mutable errorReporter = + let reporter = ProjectExternalErrorReporter(project.Id, "FS", serviceProvider) + Some(reporter:> Microsoft.VisualStudio.Shell.Interop.IVsLanguageServiceBuildErrorReporter2) + + {new Microsoft.VisualStudio.FSharp.LanguageService.IProjectSite with + member __.SourceFilesOnDisk() = this.GetProjectInfo(project.FilePath) |> fst + member __.DescriptionOfProject() = project.Name + member __.CompilerFlags() = + let _,references,options = this.GetProjectInfo(project.FilePath) + Array.concat [options; references |> Array.map(fun r -> "-r:" + r)] + member __.ProjectFileName() = project.FilePath + member __.AdviseProjectSiteChanges(_,_) = () + member __.AdviseProjectSiteCleaned(_,_) = () + member __.AdviseProjectSiteClosed(_,_) = () + member __.IsIncompleteTypeCheckEnvironment = false + member __.TargetFrameworkMoniker = "" + member __.ProjectGuid = project.Id.Id.ToString() + member __.LoadTime = System.DateTime.Now + member __.ProjectProvider = Some iProvideProjectSite + member __.AssemblyReferences() = this.GetProjectInfo(project.FilePath) |> thrd + member __.BuildErrorReporter with get () = errorReporter and + set (v) = errorReporter <- v + } + + // TODO: figure out why this is necessary + interface IVsHierarchy with + member __.SetSite(psp) = hier.SetSite(psp) + member __.GetSite(psp) = hier.GetSite(ref psp) + member __.QueryClose(pfCanClose) = hier.QueryClose(ref pfCanClose) + member __.Close() = hier.Close() + member __.GetGuidProperty(itemid, propid, pguid) = hier.GetGuidProperty(itemid, propid, ref pguid) + member __.SetGuidProperty(itemid, propid, rguid) = hier.SetGuidProperty(itemid, propid, ref rguid) + member __.GetProperty(itemid, propid, pvar) = hier.GetProperty(itemid, propid, ref pvar) + member __.SetProperty(itemid, propid, var) = hier.SetProperty(itemid, propid, var) + member __.GetNestedHierarchy(itemid, iidHierarchyNested, ppHierarchyNested, pitemidNested) = hier.GetNestedHierarchy(itemid, ref iidHierarchyNested, ref ppHierarchyNested, ref pitemidNested) + member __.GetCanonicalName(itemid, pbstrName) = hier.GetCanonicalName(itemid, ref pbstrName) + member __.ParseCanonicalName(pszName, pitemid) = hier.ParseCanonicalName(pszName, ref pitemid) + member __.Unused0() = hier.Unused0() + member __.AdviseHierarchyEvents(pEventSink, pdwCookie) = hier.AdviseHierarchyEvents(pEventSink, ref pdwCookie) + member __.UnadviseHierarchyEvents(dwCookie) = hier.UnadviseHierarchyEvents(dwCookie) + member __.Unused1() = hier.Unused1() + member __.Unused2() = hier.Unused2() + member __.Unused3() = hier.Unused3() + member __.Unused4() = hier.Unused4() + } + + member this.UpdateProjectInfoWithProjectId(projectId:ProjectId, userOpName) = + let project = workspace.CurrentSolution.GetProject(projectId) + let siteProvider = this.ProvideProjectSiteProvider(project) + this.UpdateProjectInfo(tryGetOrCreateProjectId, projectId, siteProvider.GetProjectSite(), userOpName) + + member this.UpdateProjectInfoWithPath(path, userOpName) = + let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(path, projectDisplayNameOf path) + this.UpdateProjectInfoWithProjectId(projectId, userOpName) + + [] + /// This handles commandline change notifications from the Dotnet Project-system + member this.HandleCommandLineChanges(path:string, sources:ImmutableArray, references:ImmutableArray, options:ImmutableArray) = + let fullPath p = + if Path.IsPathRooted(p) then p + else Path.Combine(Path.GetDirectoryName(path), p) + let sourcePaths = sources |> Seq.map(fun s -> fullPath s.Path) |> Seq.toArray + let referencePaths = references |> Seq.map(fun r -> fullPath r.Reference) |> Seq.toArray + projectInfo.[path] <- (sourcePaths,referencePaths,options.ToArray()) + this.UpdateProjectInfoWithPath(path, "HandleCommandLineChanges") + + member __.GetProjectInfo(path:string) = + match projectInfo.TryGetValue path with + | true, value -> value + | _ -> [||], [||], [||] + // Used to expose FSharpChecker/ProjectInfo manager to diagnostic providers // Diagnostic providers can be executed in environment that does not use MEF so they can rely only // on services exposed by the workspace @@ -217,7 +310,6 @@ type internal RoamingProfileStorageLocation(keyName: string) = member __.GetKeyNameForLanguage(languageName: string) = let unsubstitutedKeyName = keyName - match languageName with | null -> unsubstitutedKeyName | _ -> @@ -266,21 +358,15 @@ type override this.Initialize() = base.Initialize() - //initialize settings this.ComponentModel.GetService() |> ignore override this.RoslynLanguageName = FSharpConstants.FSharpLanguageName - override this.CreateWorkspace() = this.ComponentModel.GetService() - - override this.CreateLanguageService() = - FSharpLanguageService(this) - + override this.CreateLanguageService() = FSharpLanguageService(this) override this.CreateEditorFactories() = Seq.empty - override this.RegisterMiscellaneousFilesWorkspaceInformation(_) = () - -and + +type [] [, ".fs")>] [, ".fsi")>] @@ -299,7 +385,7 @@ and let projectInfoManager = package.ComponentModel.DefaultExportProvider.GetExport().Value - let projectDisplayNameOf projectFileName = + let projectDisplayNameOf projectFileName = if String.IsNullOrWhiteSpace projectFileName then projectFileName else Path.GetFileNameWithoutExtension projectFileName @@ -321,15 +407,20 @@ and let optionsAssociation = ConditionalWeakTable() + member private this.OnProjectAdded(projectId:ProjectId, _newSolution:Solution) = projectInfoManager.UpdateProjectInfoWithProjectId(projectId, "OnProjectAdded") override this.Initialize() = base.Initialize() + let workspaceChanged (args:WorkspaceChangeEventArgs) = + match args.Kind with + | WorkspaceChangeKind.ProjectAdded -> this.OnProjectAdded(args.ProjectId, args.NewSolution) + | _ -> () + 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.WorkspaceChanged.Add(workspaceChanged) + this.Workspace.DocumentClosed.Add <| fun args -> tryRemoveSingleFileProject args.Document.Project.Id - this.Workspace.DocumentClosed.Add <| fun args -> - tryRemoveSingleFileProject args.Document.Project.Id - Events.SolutionEvents.OnAfterCloseSolution.Add <| fun _ -> //checkerProvider.Checker.StopBackgroundCompile() @@ -342,7 +433,7 @@ and singleFileProjects.Keys |> Seq.iter tryRemoveSingleFileProject let ctx = System.Threading.SynchronizationContext.Current - + let rec setupProjectsAfterSolutionOpen() = async { use openedProjects = MailboxProcessor.Start <| fun inbox -> @@ -368,27 +459,27 @@ and let theme = package.ComponentModel.DefaultExportProvider.GetExport().Value theme.SetColors() - + /// Sync the information for the project - member this.SyncProject(project: AbstractProject, projectContext: IWorkspaceProjectContext, site: IProjectSite, workspace, forceUpdate, userOpName) = + member __.SyncProject(project: AbstractProject, projectContext: IWorkspaceProjectContext, site: IProjectSite, workspace, forceUpdate, userOpName) = let wellFormedFilePathSetIgnoreCase (paths: seq) = HashSet(paths |> Seq.filter isPathWellFormed |> Seq.map (fun s -> try System.IO.Path.GetFullPath(s) with _ -> s), StringComparer.OrdinalIgnoreCase) let updatedFiles = site.SourceFilesOnDisk() |> wellFormedFilePathSetIgnoreCase let originalFiles = project.GetCurrentDocuments() |> Seq.map (fun file -> file.FilePath) |> wellFormedFilePathSetIgnoreCase - + let mutable updated = forceUpdate for file in updatedFiles do if not(originalFiles.Contains(file)) then projectContext.AddSourceFile(file) updated <- true - + for file in originalFiles do if not(updatedFiles.Contains(file)) then projectContext.RemoveSourceFile(file) updated <- true - + let updatedRefs = site.AssemblyReferences() |> wellFormedFilePathSetIgnoreCase let originalRefs = project.GetCurrentMetadataReferences() |> Seq.map (fun ref -> ref.FilePath) |> wellFormedFilePathSetIgnoreCase @@ -423,7 +514,7 @@ and // update the cached options if updated then - projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId workspace, project.Id, site, project.Workspace, userOpName + ".SyncProject") + projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId workspace, project.Id, site, userOpName + ".SyncProject") member this.SetupProjectFile(siteProvider: IProvideProjectSite, workspace: VisualStudioWorkspaceImpl, userOpName) = let userOpName = userOpName + ".SetupProjectFile" @@ -435,7 +526,7 @@ and let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName) if isNull (workspace.ProjectTracker.GetProject projectId) then - projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId workspace, projectId, site, workspace, userOpName) + projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId workspace, projectId, site, userOpName) let projectContextFactory = package.ComponentModel.GetService(); let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider) @@ -474,7 +565,6 @@ and setup (siteProvider.GetProjectSite()) |> ignore member this.SetupStandAloneFile(fileName: string, fileContents: string, workspace: VisualStudioWorkspaceImpl, hier: IVsHierarchy) = - let loadTime = DateTime.Now let projectFileName = fileName let projectDisplayName = projectDisplayNameOf projectFileName @@ -506,19 +596,30 @@ and base.SetupNewTextView(textView) let textViewAdapter = package.ComponentModel.GetService() - + match textView.GetBuffer() with | (VSConstants.S_OK, textLines) -> let filename = VsTextLines.GetFilename textLines + + // CPS projects don't implement IProvideProjectSite and IVSProjectHierarchy + // Simple explanation: + // Legacy projects have IVSHierarchy and IPRojectSite + // CPS Projects and loose script files don't match VsRunningDocumentTable.FindDocumentWithoutLocking(package.RunningDocumentTable,filename) with | Some (hier, _) -> match hier with - | :? IProvideProjectSite as siteProvider when not (IsScript(filename)) -> + | :? IProvideProjectSite as siteProvider when not (IsScript(filename)) -> this.SetupProjectFile(siteProvider, this.Workspace, "SetupNewTextView") - | _ -> + | _ when not (IsScript(filename)) -> + let docId = this.Workspace.CurrentSolution.GetDocumentIdsWithFilePath(filename).FirstOrDefault() + match docId with + | null -> + let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter) + this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier) + | id -> + projectInfoManager.UpdateProjectInfoWithProjectId(id.ProjectId, "SetupNewTextView") + | _ -> let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter) this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier) | _ -> () | _ -> () - - diff --git a/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs b/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs index 7d91599a7896174338f14a5b3a856276d6f409aa..a7367999ab4580e038d9a7e5c88dbc14bd2c8243 100644 --- a/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs +++ b/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs @@ -46,7 +46,7 @@ open Microsoft.FSharp.Compiler.SourceCodeServices type private IHaveCheckOptions = abstract OriginalCheckOptions : unit -> string[] * FSharpProjectOptions -/// Convert from FSharpProjectOptions into IProjectSite. +/// Convert from FSharpProjectOptions into IProjectSite. type private ProjectSiteOfScriptFile(filename:string, referencedProjectFileNames, checkOptions : FSharpProjectOptions) = interface IProjectSite with override this.SourceFilesOnDisk() = checkOptions.SourceFiles @@ -192,10 +192,8 @@ type internal ProjectSitesAndFiles() = if SourceFile.MustBeSingleFileProject(filename) then Debug.Assert(false, ".fsx or .fsscript should have been treated as implicit project") failwith ".fsx or .fsscript should have been treated as implicit project" - new ProjectSiteOfSingleFile(filename) :> IProjectSite - - + static member GetReferencedProjectSites(projectSite:IProjectSite, serviceProvider:System.IServiceProvider) = referencedProvideProjectSites (projectSite, serviceProvider) |> Seq.map (fun (_, ps) -> ps.GetProjectSite())