提交 602daf80 编写于 作者: K Kevin Ransom (msft) 提交者: GitHub

Another go at --- Map workspace to iprojectsite (#3564)

* Saved

* SDK editor support

* Address merge issues

* Feedback

* reduce delta

* invalidate ide when a new file is discovered

* Go faster stripes

* feedback + refactor

* tryFindIndex

* Cleanup + Ensure that FSharp.Core.BuildFromSource.proj works at designtime

* final clean up

* label for HandleCommandLineChanges

* ensure some buildfromsource porojects load
上级 4769a923
...@@ -38,7 +38,8 @@ ...@@ -38,7 +38,8 @@
<Target Name="CopyAndSubstituteTextFiles" <Target Name="CopyAndSubstituteTextFiles"
BeforeTargets="Compile" BeforeTargets="Compile"
Inputs="@(CopyAndSubstituteText)" Inputs="@(CopyAndSubstituteText)"
Outputs="@(CopyAndSubstituteText->'$(OutDir)%(TargetFilename)')" > Outputs="@(CopyAndSubstituteText->'$(OutDir)%(TargetFilename)')"
Condition="'$(DesignTimeBuild)' != 'true'">
<ItemGroup> <ItemGroup>
<Results Include="@(CopyAndSubstituteText->'$(OutDir)%(TargetFilename)')"> <Results Include="@(CopyAndSubstituteText->'$(OutDir)%(TargetFilename)')">
......
...@@ -20,7 +20,7 @@ if ERRORLEVEL 1 echo Error: failed && goto :failure ...@@ -20,7 +20,7 @@ if ERRORLEVEL 1 echo Error: failed && goto :failure
rem build and pack tools rem build and pack tools
dotnet restore %__scriptpath%fsharp\FSharp.Compiler.nuget\FSharp.Compiler.nuget.BuildFromSource.fsproj dotnet restore %__scriptpath%fsharp\FSharp.Compiler.nuget\FSharp.Compiler.nuget.BuildFromSource.fsproj
if ERRORLEVEL 1 echo Error: failed && goto :failure 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 if ERRORLEVEL 1 echo Error: failed && goto :failure
goto :success goto :success
......
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
namespace Microsoft.FSharp namespace Microsoft.FSharp
open System.Reflection
[<assembly:System.Runtime.CompilerServices.InternalsVisibleTo("VisualFSharp.Unittests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007D1FA57C4AED9F0A32E84AA0FAEFD0DE9E8FD6AEC8F87FB03766C834C99921EB23BE79AD9D5DCC1DD9AD236132102900B723CF980957FC4E177108FC607774F29E8320E92EA05ECE4E821C0A5EFE8F1645C4C0C93C1AB99285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF0FC4963D261C8A12436518206DC093344D5AD293")>]
[<assembly:System.Runtime.CompilerServices.InternalsVisibleTo("VisualFSharp.Unittests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007D1FA57C4AED9F0A32E84AA0FAEFD0DE9E8FD6AEC8F87FB03766C834C99921EB23BE79AD9D5DCC1DD9AD236132102900B723CF980957FC4E177108FC607774F29E8320E92EA05ECE4E821C0A5EFE8F1645C4C0C93C1AB99285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF0FC4963D261C8A12436518206DC093344D5AD293")>]
do() do()
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<OtherFlags>$(OtherFlags) --warnon:1182 --compiling-fslib --compiling-fslib-40 --maxerrors:20 --extraoptimizationloops:1</OtherFlags> <OtherFlags>$(OtherFlags) --warnon:1182 --compiling-fslib --compiling-fslib-40 --maxerrors:20 --extraoptimizationloops:1</OtherFlags>
</PropertyGroup> </PropertyGroup>
<Import Project = "$(MSBuildThisFileDirectory)..\..\FSharpSource.BuildFromSource.targets" /> <Import Project="$(MSBuildThisFileDirectory)..\..\FSharpSource.BuildFromSource.targets" />
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="FSCore.resx"> <EmbeddedResource Include="FSCore.resx">
<Link>FSCore.resx</Link> <Link>FSCore.resx</Link>
...@@ -212,7 +212,7 @@ ...@@ -212,7 +212,7 @@
<!-- NOTE: The optdata and sigdata files are no longer needed by the F# compiler (the information is --> <!-- NOTE: The optdata and sigdata files are no longer needed by the F# compiler (the information is -->
<!-- integrated as resources into more recent FSharp.Core.dll's. However they are still produced to --> <!-- integrated as resources into more recent FSharp.Core.dll's. However they are still produced to -->
<!-- allow older versions of the F# compiler to reference more recent FSharp.Core packages --> <!-- allow older versions of the F# compiler to reference more recent FSharp.Core packages -->
<Target Name="CopyToBuiltBin" BeforeTargets="AfterCompile" AfterTargets="CoreCompile" > <Target Name="CopyToBuiltBin" BeforeTargets="AfterCompile" AfterTargets="CoreCompile" Condition="'$(DesignTimeBuild)' != 'true'">
<ItemGroup> <ItemGroup>
<BuiltProjectOutputGroupKeyOutput Include="$(IntermediateOutputPath)/FSharp.Core.sigdata" /> <BuiltProjectOutputGroupKeyOutput Include="$(IntermediateOutputPath)/FSharp.Core.sigdata" />
<BuiltProjectOutputGroupKeyOutput Include="$(IntermediateOutputPath)/FSharp.Core.optdata" /> <BuiltProjectOutputGroupKeyOutput Include="$(IntermediateOutputPath)/FSharp.Core.optdata" />
......
...@@ -2468,7 +2468,6 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i ...@@ -2468,7 +2468,6 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i
do tcConfigB.resolutionEnvironment <- ResolutionEnvironment.EditingOrCompilation false do tcConfigB.resolutionEnvironment <- ResolutionEnvironment.EditingOrCompilation false
do tcConfigB.useSimpleResolution <- true do tcConfigB.useSimpleResolution <- true
do SetTargetProfile tcConfigB "netcore" // always assume System.Runtime codegen do SetTargetProfile tcConfigB "netcore" // always assume System.Runtime codegen
//do SetTargetProfile tcConfigB "privatecorelib" // always assume System.Private.CoreLib codegen
#endif #endif
// Preset: --optimize+ -g --tailcalls+ (see 4505) // Preset: --optimize+ -g --tailcalls+ (see 4505)
......
...@@ -1681,8 +1681,11 @@ type IncrementalBuilder(tcGlobals,frameworkTcImports, nonFrameworkAssemblyInputs ...@@ -1681,8 +1681,11 @@ type IncrementalBuilder(tcGlobals,frameworkTcImports, nonFrameworkAssemblyInputs
/// CreateIncrementalBuilder (for background type checking). Note that fsc.fs also /// CreateIncrementalBuilder (for background type checking). Note that fsc.fs also
/// creates an incremental builder used by the command line compiler. /// 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) = 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 { cancellable {
// Trap and report warnings and errors from creation. // Trap and report warnings and errors from creation.
use errorScope = new ErrorScope() use errorScope = new ErrorScope()
let! builderOpt = let! builderOpt =
...@@ -1695,23 +1698,38 @@ type IncrementalBuilder(tcGlobals,frameworkTcImports, nonFrameworkAssemblyInputs ...@@ -1695,23 +1698,38 @@ type IncrementalBuilder(tcGlobals,frameworkTcImports, nonFrameworkAssemblyInputs
/// Create a type-check configuration /// Create a type-check configuration
let tcConfigB, sourceFilesNew = 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 // 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) 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 // 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 // Could detect well-known assemblies--ie System.dll--and open them with read-locks
tcConfigB.openBinariesInMemory <- true tcConfigB.openBinariesInMemory <- true
tcConfigB.resolutionEnvironment <- (ReferenceResolver.ResolutionEnvironment.EditingOrCompilation true) tcConfigB.resolutionEnvironment <- (ReferenceResolver.ResolutionEnvironment.EditingOrCompilation true)
tcConfigB.conditionalCompilationDefines <- tcConfigB.conditionalCompilationDefines <-
let define = if useScriptResolutionRules then "INTERACTIVE" else "COMPILED" let define = if useScriptResolutionRules then "INTERACTIVE" else "COMPILED"
define::tcConfigB.conditionalCompilationDefines define::tcConfigB.conditionalCompilationDefines
tcConfigB.projectReferences <- projectReferences tcConfigB.projectReferences <- projectReferences
#if COMPILER_SERVICE_ASSUMES_DOTNETCORE_COMPILATION #if COMPILER_SERVICE_ASSUMES_DOTNETCORE_COMPILATION
tcConfigB.useSimpleResolution <- true // turn off msbuild resolution tcConfigB.useSimpleResolution <- true // turn off msbuild resolution
#else
tcConfigB.useSimpleResolution <- (getSwitchValue useSimpleResolutionSwitch) |> Option.isSome
#endif #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 // Apply command-line arguments and collect more source files if they are in the arguments
let sourceFilesNew = let sourceFilesNew =
try try
...@@ -1725,12 +1743,16 @@ type IncrementalBuilder(tcGlobals,frameworkTcImports, nonFrameworkAssemblyInputs ...@@ -1725,12 +1743,16 @@ type IncrementalBuilder(tcGlobals,frameworkTcImports, nonFrameworkAssemblyInputs
// Never open PDB files for the language service, even if --standalone is specified // Never open PDB files for the language service, even if --standalone is specified
tcConfigB.openDebugInformationForLaterStaticLinking <- false 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 tcConfigB, sourceFilesNew
match loadClosureOpt with match loadClosureOpt with
| Some loadClosure -> | Some loadClosure ->
let dllReferences = let dllReferences =
[for reference in tcConfigB.referencedDLLs do [for reference in tcConfigB.referencedDLLs do
// If there's (one or more) resolutions of closure references then yield them all // 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 match loadClosure.References |> List.tryFind (fun (resolved,_)->resolved=reference.Text) with
......
...@@ -3139,7 +3139,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, reactorOps: IReactorOperatio ...@@ -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 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) let! tcErrors, tcFileResult = Parser.CheckOneFile(parseResults, source, filename, "project", tcConfig, tcGlobals, tcImports, tcState, Some loadClosure, backgroundDiagnostics, reactorOps, (fun () -> true), None, userOpName)
return return
match tcFileResult with match tcFileResult with
| Parser.TypeCheckAborted.No scope -> | Parser.TypeCheckAborted.No scope ->
...@@ -3150,7 +3150,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, reactorOps: IReactorOperatio ...@@ -3150,7 +3150,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, reactorOps: IReactorOperatio
| _ -> | _ ->
failwith "unexpected aborted" failwith "unexpected aborted"
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// CompilerEnvironment, DebuggerEnvironment // CompilerEnvironment, DebuggerEnvironment
// //
......
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. // 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" #nowarn "40"
open System open System
open System.Collections.Concurrent open System.Collections.Concurrent
open System.Collections.Generic open System.Collections.Generic
open System.Collections.Immutable
open System.ComponentModel.Composition open System.ComponentModel.Composition
open System.Diagnostics
open System.IO
open System.Linq
open System.Runtime.CompilerServices open System.Runtime.CompilerServices
open System.Runtime.InteropServices open System.Runtime.InteropServices
open System.IO open System.Threading
open System.Diagnostics
open Microsoft.FSharp.Compiler.CompileOps open Microsoft.FSharp.Compiler.CompileOps
open Microsoft.FSharp.Compiler.SourceCodeServices open Microsoft.FSharp.Compiler.SourceCodeServices
open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library
open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Diagnostics open Microsoft.CodeAnalysis.Diagnostics
...@@ -23,6 +27,7 @@ open Microsoft.CodeAnalysis.Options ...@@ -23,6 +27,7 @@ open Microsoft.CodeAnalysis.Options
open Microsoft.VisualStudio open Microsoft.VisualStudio
open Microsoft.VisualStudio.Editor open Microsoft.VisualStudio.Editor
open Microsoft.VisualStudio.TextManager.Interop open Microsoft.VisualStudio.TextManager.Interop
open Microsoft.VisualStudio.LanguageServices
open Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService open Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService
open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
open Microsoft.VisualStudio.LanguageServices.Implementation.TaskList open Microsoft.VisualStudio.LanguageServices.Implementation.TaskList
...@@ -78,7 +83,6 @@ type internal FSharpCheckerProvider ...@@ -78,7 +83,6 @@ type internal FSharpCheckerProvider
member this.Checker = checker.Value 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. /// 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) type Refreshable<'T> = 'T * (bool -> 'T)
...@@ -87,22 +91,33 @@ 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. // 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). // 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. // The main entrypoints are TryGetOptionsForDocumentOrProject and TryGetOptionsForEditingDocumentOrProject.
[<Export(typeof<FSharpProjectOptionsManager>); Composition.Shared>] [<Export(typeof<FSharpProjectOptionsManager>); Composition.Shared>]
type internal FSharpProjectOptionsManager type internal FSharpProjectOptionsManager
[<ImportingConstructor>] [<ImportingConstructor>]
( (
checkerProvider: FSharpCheckerProvider, checkerProvider: FSharpCheckerProvider,
[<Import(typeof<VisualStudioWorkspace>)>] workspace: VisualStudioWorkspaceImpl,
[<Import(typeof<SVsServiceProvider>)>] serviceProvider: System.IServiceProvider [<Import(typeof<SVsServiceProvider>)>] 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<ProjectId, Refreshable<ProjectId[] * FSharpProjectOptions>>() let projectTable = ConcurrentDictionary<ProjectId, Refreshable<ProjectId[] * FSharpProjectOptions>>()
// A table of information about single-file projects. Currently we only need the load time of each such file, plus // 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 // the original options for editing
let singleFileProjectTable = ConcurrentDictionary<ProjectId, DateTime * FSharpProjectOptions>() let singleFileProjectTable = ConcurrentDictionary<ProjectId, DateTime * FSharpProjectOptions>()
// Accumulate sources and references for each project file
let projectInfo = new ConcurrentDictionary<string, string[]*string[]*string[]>()
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 /// Clear a project from the project table
member this.ClearInfoForProject(projectId: ProjectId) = member this.ClearInfoForProject(projectId: ProjectId) =
projectTable.TryRemove(projectId) |> ignore projectTable.TryRemove(projectId) |> ignore
...@@ -124,7 +139,7 @@ type internal FSharpProjectOptionsManager ...@@ -124,7 +139,7 @@ type internal FSharpProjectOptionsManager
member this.AddOrUpdateSingleFileProject(projectId, data) = member this.AddOrUpdateSingleFileProject(projectId, data) =
singleFileProjectTable.[projectId] <- data singleFileProjectTable.[projectId] <- data
/// Get the exact options for a single-file script /// Get the exact options for a single-file script
member this.ComputeSingleFileOptions (tryGetOrCreateProjectId, fileName, loadTime, fileContents, workspace: Workspace) = async { member this.ComputeSingleFileOptions (tryGetOrCreateProjectId, fileName, loadTime, fileContents, workspace: Workspace) = async {
let extraProjectInfo = Some(box workspace) let extraProjectInfo = Some(box workspace)
...@@ -145,7 +160,7 @@ type internal FSharpProjectOptionsManager ...@@ -145,7 +160,7 @@ type internal FSharpProjectOptionsManager
} }
/// Update the info for a project in the project table /// 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 -> this.AddOrUpdateProject(projectId, (fun isRefresh ->
let extraProjectInfo = Some(box workspace) let extraProjectInfo = Some(box workspace)
let tryGetOptionsForReferencedProject f = f |> tryGetOrCreateProjectId |> Option.bind this.TryGetOptionsForProject let tryGetOptionsForReferencedProject f = f |> tryGetOrCreateProjectId |> Option.bind this.TryGetOptionsForProject
...@@ -153,7 +168,7 @@ type internal FSharpProjectOptionsManager ...@@ -153,7 +168,7 @@ type internal FSharpProjectOptionsManager
let referencedProjectIds = referencedProjects |> Array.choose tryGetOrCreateProjectId let referencedProjectIds = referencedProjects |> Array.choose tryGetOrCreateProjectId
checkerProvider.Checker.InvalidateConfiguration(options, startBackgroundCompileIfAlreadySeen = not isRefresh, userOpName= userOpName + ".UpdateProjectInfo") checkerProvider.Checker.InvalidateConfiguration(options, startBackgroundCompileIfAlreadySeen = not isRefresh, userOpName= userOpName + ".UpdateProjectInfo")
referencedProjectIds, options)) referencedProjectIds, options))
/// Get compilation defines relevant for syntax processing. /// Get compilation defines relevant for syntax processing.
/// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project /// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project
/// options for a script. /// options for a script.
...@@ -204,6 +219,84 @@ type internal FSharpProjectOptionsManager ...@@ -204,6 +219,84 @@ type internal FSharpProjectOptionsManager
| true, (_loadTime, originalOptions) -> Some originalOptions | true, (_loadTime, originalOptions) -> Some originalOptions
| _ -> this.TryGetOptionsForProject(projectId) | _ -> 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)
[<Export>]
/// This handles commandline change notifications from the Dotnet Project-system
member this.HandleCommandLineChanges(path:string, sources:ImmutableArray<CommandLineSourceFile>, references:ImmutableArray<CommandLineReference>, options:ImmutableArray<string>) =
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 // 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 // Diagnostic providers can be executed in environment that does not use MEF so they can rely only
// on services exposed by the workspace // on services exposed by the workspace
...@@ -217,7 +310,6 @@ type internal RoamingProfileStorageLocation(keyName: string) = ...@@ -217,7 +310,6 @@ type internal RoamingProfileStorageLocation(keyName: string) =
member __.GetKeyNameForLanguage(languageName: string) = member __.GetKeyNameForLanguage(languageName: string) =
let unsubstitutedKeyName = keyName let unsubstitutedKeyName = keyName
match languageName with match languageName with
| null -> unsubstitutedKeyName | null -> unsubstitutedKeyName
| _ -> | _ ->
...@@ -266,21 +358,15 @@ type ...@@ -266,21 +358,15 @@ type
override this.Initialize() = override this.Initialize() =
base.Initialize() base.Initialize()
//initialize settings
this.ComponentModel.GetService<SettingsPersistence.ISettings>() |> ignore this.ComponentModel.GetService<SettingsPersistence.ISettings>() |> ignore
override this.RoslynLanguageName = FSharpConstants.FSharpLanguageName override this.RoslynLanguageName = FSharpConstants.FSharpLanguageName
override this.CreateWorkspace() = this.ComponentModel.GetService<VisualStudioWorkspaceImpl>() override this.CreateWorkspace() = this.ComponentModel.GetService<VisualStudioWorkspaceImpl>()
override this.CreateLanguageService() = FSharpLanguageService(this)
override this.CreateLanguageService() =
FSharpLanguageService(this)
override this.CreateEditorFactories() = Seq.empty<IVsEditorFactory> override this.CreateEditorFactories() = Seq.empty<IVsEditorFactory>
override this.RegisterMiscellaneousFilesWorkspaceInformation(_) = () override this.RegisterMiscellaneousFilesWorkspaceInformation(_) = ()
and type
[<Guid(FSharpConstants.languageServiceGuidString)>] [<Guid(FSharpConstants.languageServiceGuidString)>]
[<ProvideLanguageExtension(typeof<FSharpLanguageService>, ".fs")>] [<ProvideLanguageExtension(typeof<FSharpLanguageService>, ".fs")>]
[<ProvideLanguageExtension(typeof<FSharpLanguageService>, ".fsi")>] [<ProvideLanguageExtension(typeof<FSharpLanguageService>, ".fsi")>]
...@@ -299,7 +385,7 @@ and ...@@ -299,7 +385,7 @@ and
let projectInfoManager = package.ComponentModel.DefaultExportProvider.GetExport<FSharpProjectOptionsManager>().Value let projectInfoManager = package.ComponentModel.DefaultExportProvider.GetExport<FSharpProjectOptionsManager>().Value
let projectDisplayNameOf projectFileName = let projectDisplayNameOf projectFileName =
if String.IsNullOrWhiteSpace projectFileName then projectFileName if String.IsNullOrWhiteSpace projectFileName then projectFileName
else Path.GetFileNameWithoutExtension projectFileName else Path.GetFileNameWithoutExtension projectFileName
...@@ -321,15 +407,20 @@ and ...@@ -321,15 +407,20 @@ and
let optionsAssociation = ConditionalWeakTable<IWorkspaceProjectContext, string[]>() let optionsAssociation = ConditionalWeakTable<IWorkspaceProjectContext, string[]>()
member private this.OnProjectAdded(projectId:ProjectId, _newSolution:Solution) = projectInfoManager.UpdateProjectInfoWithProjectId(projectId, "OnProjectAdded")
override this.Initialize() = override this.Initialize() =
base.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(Completion.CompletionOptions.BlockForCompletionItems, FSharpConstants.FSharpLanguageName, false)
this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Shared.Options.ServiceFeatureOnOffOptions.ClosedFileDiagnostic, FSharpConstants.FSharpLanguageName, Nullable 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 _ -> Events.SolutionEvents.OnAfterCloseSolution.Add <| fun _ ->
//checkerProvider.Checker.StopBackgroundCompile() //checkerProvider.Checker.StopBackgroundCompile()
...@@ -342,7 +433,7 @@ and ...@@ -342,7 +433,7 @@ and
singleFileProjects.Keys |> Seq.iter tryRemoveSingleFileProject singleFileProjects.Keys |> Seq.iter tryRemoveSingleFileProject
let ctx = System.Threading.SynchronizationContext.Current let ctx = System.Threading.SynchronizationContext.Current
let rec setupProjectsAfterSolutionOpen() = let rec setupProjectsAfterSolutionOpen() =
async { async {
use openedProjects = MailboxProcessor.Start <| fun inbox -> use openedProjects = MailboxProcessor.Start <| fun inbox ->
...@@ -368,27 +459,27 @@ and ...@@ -368,27 +459,27 @@ and
let theme = package.ComponentModel.DefaultExportProvider.GetExport<ISetThemeColors>().Value let theme = package.ComponentModel.DefaultExportProvider.GetExport<ISetThemeColors>().Value
theme.SetColors() theme.SetColors()
/// Sync the information for the project /// 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<string>) = let wellFormedFilePathSetIgnoreCase (paths: seq<string>) =
HashSet(paths |> Seq.filter isPathWellFormed |> Seq.map (fun s -> try System.IO.Path.GetFullPath(s) with _ -> s), StringComparer.OrdinalIgnoreCase) 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 updatedFiles = site.SourceFilesOnDisk() |> wellFormedFilePathSetIgnoreCase
let originalFiles = project.GetCurrentDocuments() |> Seq.map (fun file -> file.FilePath) |> wellFormedFilePathSetIgnoreCase let originalFiles = project.GetCurrentDocuments() |> Seq.map (fun file -> file.FilePath) |> wellFormedFilePathSetIgnoreCase
let mutable updated = forceUpdate let mutable updated = forceUpdate
for file in updatedFiles do for file in updatedFiles do
if not(originalFiles.Contains(file)) then if not(originalFiles.Contains(file)) then
projectContext.AddSourceFile(file) projectContext.AddSourceFile(file)
updated <- true updated <- true
for file in originalFiles do for file in originalFiles do
if not(updatedFiles.Contains(file)) then if not(updatedFiles.Contains(file)) then
projectContext.RemoveSourceFile(file) projectContext.RemoveSourceFile(file)
updated <- true updated <- true
let updatedRefs = site.AssemblyReferences() |> wellFormedFilePathSetIgnoreCase let updatedRefs = site.AssemblyReferences() |> wellFormedFilePathSetIgnoreCase
let originalRefs = project.GetCurrentMetadataReferences() |> Seq.map (fun ref -> ref.FilePath) |> wellFormedFilePathSetIgnoreCase let originalRefs = project.GetCurrentMetadataReferences() |> Seq.map (fun ref -> ref.FilePath) |> wellFormedFilePathSetIgnoreCase
...@@ -423,7 +514,7 @@ and ...@@ -423,7 +514,7 @@ and
// update the cached options // update the cached options
if updated then 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) = member this.SetupProjectFile(siteProvider: IProvideProjectSite, workspace: VisualStudioWorkspaceImpl, userOpName) =
let userOpName = userOpName + ".SetupProjectFile" let userOpName = userOpName + ".SetupProjectFile"
...@@ -435,7 +526,7 @@ and ...@@ -435,7 +526,7 @@ and
let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName) let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName)
if isNull (workspace.ProjectTracker.GetProject projectId) then 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<IWorkspaceProjectContextFactory>(); let projectContextFactory = package.ComponentModel.GetService<IWorkspaceProjectContextFactory>();
let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider) let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider)
...@@ -474,7 +565,6 @@ and ...@@ -474,7 +565,6 @@ and
setup (siteProvider.GetProjectSite()) |> ignore setup (siteProvider.GetProjectSite()) |> ignore
member this.SetupStandAloneFile(fileName: string, fileContents: string, workspace: VisualStudioWorkspaceImpl, hier: IVsHierarchy) = member this.SetupStandAloneFile(fileName: string, fileContents: string, workspace: VisualStudioWorkspaceImpl, hier: IVsHierarchy) =
let loadTime = DateTime.Now let loadTime = DateTime.Now
let projectFileName = fileName let projectFileName = fileName
let projectDisplayName = projectDisplayNameOf projectFileName let projectDisplayName = projectDisplayNameOf projectFileName
...@@ -506,19 +596,30 @@ and ...@@ -506,19 +596,30 @@ and
base.SetupNewTextView(textView) base.SetupNewTextView(textView)
let textViewAdapter = package.ComponentModel.GetService<IVsEditorAdaptersFactoryService>() let textViewAdapter = package.ComponentModel.GetService<IVsEditorAdaptersFactoryService>()
match textView.GetBuffer() with match textView.GetBuffer() with
| (VSConstants.S_OK, textLines) -> | (VSConstants.S_OK, textLines) ->
let filename = VsTextLines.GetFilename 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 match VsRunningDocumentTable.FindDocumentWithoutLocking(package.RunningDocumentTable,filename) with
| Some (hier, _) -> | Some (hier, _) ->
match hier with match hier with
| :? IProvideProjectSite as siteProvider when not (IsScript(filename)) -> | :? IProvideProjectSite as siteProvider when not (IsScript(filename)) ->
this.SetupProjectFile(siteProvider, this.Workspace, "SetupNewTextView") 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) let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter)
this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier) this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier)
| _ -> () | _ -> ()
| _ -> () | _ -> ()
...@@ -46,7 +46,7 @@ open Microsoft.FSharp.Compiler.SourceCodeServices ...@@ -46,7 +46,7 @@ open Microsoft.FSharp.Compiler.SourceCodeServices
type private IHaveCheckOptions = type private IHaveCheckOptions =
abstract OriginalCheckOptions : unit -> string[] * FSharpProjectOptions abstract OriginalCheckOptions : unit -> string[] * FSharpProjectOptions
/// Convert from FSharpProjectOptions into IProjectSite. /// Convert from FSharpProjectOptions into IProjectSite.
type private ProjectSiteOfScriptFile(filename:string, referencedProjectFileNames, checkOptions : FSharpProjectOptions) = type private ProjectSiteOfScriptFile(filename:string, referencedProjectFileNames, checkOptions : FSharpProjectOptions) =
interface IProjectSite with interface IProjectSite with
override this.SourceFilesOnDisk() = checkOptions.SourceFiles override this.SourceFilesOnDisk() = checkOptions.SourceFiles
...@@ -192,10 +192,8 @@ type internal ProjectSitesAndFiles() = ...@@ -192,10 +192,8 @@ type internal ProjectSitesAndFiles() =
if SourceFile.MustBeSingleFileProject(filename) then if SourceFile.MustBeSingleFileProject(filename) then
Debug.Assert(false, ".fsx or .fsscript should have been treated as implicit project") Debug.Assert(false, ".fsx or .fsscript should have been treated as implicit project")
failwith ".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 new ProjectSiteOfSingleFile(filename) :> IProjectSite
static member GetReferencedProjectSites(projectSite:IProjectSite, serviceProvider:System.IServiceProvider) = static member GetReferencedProjectSites(projectSite:IProjectSite, serviceProvider:System.IServiceProvider) =
referencedProvideProjectSites (projectSite, serviceProvider) referencedProvideProjectSites (projectSite, serviceProvider)
|> Seq.map (fun (_, ps) -> ps.GetProjectSite()) |> Seq.map (fun (_, ps) -> ps.GetProjectSite())
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册