diff --git a/.gitignore b/.gitignore
index e4d0670940f..0733a5fdbce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -78,8 +78,7 @@ tests/*FSharp_Failures.lst
tests/fsharpqa/Source/CodeGen/EmittedIL/StaticInit/StaticInit_Module01.dll
tests/fsharpqa/Source/CodeGen/EmittedIL/StaticInit/StaticInit_Module01.pdb
tests/XFSharpQA_Failures.log.*
-vsintegration/src/vs/FsPkgs/FSharp.Project/FS/FSharp.ProjectSystem.FSharp.fsi
-vsintegration/src/vs/FsPkgs/FSharp.Project/FS/ctofiles/
+vsintegration/src/FSharp.ProjectSystem.FSharp/ctofiles
tests/fsharpqa/Source/CodeGen/EmittedIL/QueryExpressionStepping/Utils.dll
tests/fsharpqa/Source/CodeGen/EmittedIL/ComputationExpressions/ComputationExprLibrary.dll
tests/fsharpqa/Source/*FSharpQA_Failures.env
diff --git a/.nuget/NuGet.Config b/.nuget/NuGet.Config
index baef485daec..f2dee4af8f9 100644
--- a/.nuget/NuGet.Config
+++ b/.nuget/NuGet.Config
@@ -7,6 +7,7 @@
+
\ No newline at end of file
diff --git a/README.md b/README.md
index adfd5dd3412..f9e3eef659e 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,7 @@ For F# 4.0 development
- [.NET 3.5](http://www.microsoft.com/en-us/download/details.aspx?id=21)
- [.NET 4.5](http://www.microsoft.com/en-us/download/details.aspx?id=30653)
- [.NET 4.5.1](http://www.microsoft.com/en-us/download/details.aspx?id=40779)
+- [.NET 4.6](https://www.microsoft.com/en-us/download/details.aspx?id=48137)
- [MSBuild 12.0](http://www.microsoft.com/en-us/download/details.aspx?id=40760)
- [Windows 7 SDK](http://www.microsoft.com/en-us/download/details.aspx?id=8279)
- [Windows 8 SDK](http://msdn.microsoft.com/en-us/windows/desktop/hh852363.aspx)
diff --git a/packages.config b/packages.config
index f311d7fb273..b507dc8c264 100644
--- a/packages.config
+++ b/packages.config
@@ -4,4 +4,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/FSharpSource.targets b/src/FSharpSource.targets
index d987dd2cb21..709c33924ef 100644
--- a/src/FSharpSource.targets
+++ b/src/FSharpSource.targets
@@ -112,11 +112,14 @@
2.0.32.0.3.0$(FSharpSourcesRoot)\..\packages\FsCheck.$(FsCheckVersion)\lib\
+ 1.0.30
+ 1.1.37
+ 1.2.0-beta1-20160218-02
- v3.5
+ v3.5$(DefineConstants);FSHARP_CORE_2_0$(DefineConstants);RUNTIME$(DefineConstants);FX_ATLEAST_35
@@ -136,7 +139,7 @@
- v4.5
+ v4.5$(DefineConstants);FSHARP_CORE_4_5$(DefineConstants);FX_ATLEAST_45$(DefineConstants);FX_ATLEAST_40
@@ -203,7 +206,7 @@
$(DefineConstants);DONT_INCLUDE_DEPRECATED$(DefineConstants);QUERIES_IN_FSLIBProfile47
- v4.0
+ v4.0
@@ -239,7 +242,7 @@
$(DefineConstants);FX_EVENTWAITHANDLE_NO_IDISPOSABLEtrueProfile7
- v4.5
+ v4.5
@@ -275,7 +278,7 @@
$(DefineConstants);FX_NO_CONCURRENT_DICTIONARY$(DefineConstants);FX_ATLEAST_LINQProfile78
- v4.5
+ v4.5
@@ -311,12 +314,12 @@
$(DefineConstants);FX_NO_CONCURRENT_DICTIONARY$(DefineConstants);FX_ATLEAST_LINQProfile259
- v4.5
+ v4.5
- v3.0
+ v3.0$(DefineConstants);SILVERLIGHT$(DefineConstants);FX_NO_CANCELLATIONTOKEN_CLASSES$(DefineConstants);FX_NO_EXCEPTIONDISPATCHINFO
@@ -396,7 +399,7 @@
$(DefineConstants);PUT_TYPE_PROVIDERS_IN_FSCORE;$(DefineConstants);FX_ATLEAST_LINQSilverlight
- v4.0
+ v4.0v4.0
@@ -439,14 +442,14 @@
$(DefineConstants);FX_ATLEAST_LINQ$(DefineConstants);TARGET_SILVERLIGHT_5_0Silverlight
- v5.0
+ v5.0v5.0Software\Microsoft\Microsoft SDKs\$(TargetFrameworkIdentifier)$(MSBuildExtensionsPath32)\..\Reference Assemblies\Microsoft\Framework\Silverlight\v5.0
- v4.0
+ v4.0WindowsPhoneSilverlight$(DefineConstants);SILVERLIGHT
@@ -494,7 +497,7 @@
- v2.0
+ v2.0CompactFramework$(DefineConstants);FX_ATLEAST_COMPACT_FRAMEWORK_20$(DefineConstants);FX_NO_CANCELLATIONTOKEN_CLASSES
@@ -583,7 +586,7 @@
- v3.5
+ v3.5CompactFramework$(DefineConstants);FX_ATLEAST_COMPACT_FRAMEWORK_35$(DefineConstants);FX_NO_CANCELLATIONTOKEN_CLASSES
diff --git a/src/fsharp/FSharp.Compiler/InternalsVisibleTo.fs b/src/fsharp/FSharp.Compiler/InternalsVisibleTo.fs
index b3a4f75fc52..bcf9fa96293 100644
--- a/src/fsharp/FSharp.Compiler/InternalsVisibleTo.fs
+++ b/src/fsharp/FSharp.Compiler/InternalsVisibleTo.fs
@@ -8,6 +8,7 @@ open System.Reflection
[]
[]
[]
+[]
[]
[]
[]
diff --git a/src/fsharp/FSharp.Data.TypeProviders/FSharp.Data.TypeProviders.fsproj b/src/fsharp/FSharp.Data.TypeProviders/FSharp.Data.TypeProviders.fsproj
index ccb67526e5c..810ecac2122 100644
--- a/src/fsharp/FSharp.Data.TypeProviders/FSharp.Data.TypeProviders.fsproj
+++ b/src/fsharp/FSharp.Data.TypeProviders/FSharp.Data.TypeProviders.fsproj
@@ -11,7 +11,6 @@
LibraryFSharp.Data.TypeProviderstrue
- v4.0{cb7d20c4-6506-406d-9144-5342c3595f03}$(OtherFlags) --warnon:1182
diff --git a/src/fsharp/FSharp.LanguageService.Compiler/InternalsVisibleTo.fs b/src/fsharp/FSharp.LanguageService.Compiler/InternalsVisibleTo.fs
index 7ecc3a74ff8..f41722d1326 100644
--- a/src/fsharp/FSharp.LanguageService.Compiler/InternalsVisibleTo.fs
+++ b/src/fsharp/FSharp.LanguageService.Compiler/InternalsVisibleTo.fs
@@ -8,6 +8,7 @@ open System.Reflection
[]
[]
[]
+[]
[]
[]
[]
diff --git a/vsintegration/deployment/EnableOpenSource/EnableOpenSource.csproj b/vsintegration/deployment/EnableOpenSource/EnableOpenSource.csproj
index ac7cee170a2..5249cdb7525 100644
--- a/vsintegration/deployment/EnableOpenSource/EnableOpenSource.csproj
+++ b/vsintegration/deployment/EnableOpenSource/EnableOpenSource.csproj
@@ -37,7 +37,7 @@
PropertiesEnableOpenSourceEnableOpenSource
- v4.5
+ v4.6falsefalsefalse
diff --git a/vsintegration/deployment/EnableOpenSource/source.extension.vsixmanifest b/vsintegration/deployment/EnableOpenSource/source.extension.vsixmanifest
index 217604fe881..7f550ceb259 100644
--- a/vsintegration/deployment/EnableOpenSource/source.extension.vsixmanifest
+++ b/vsintegration/deployment/EnableOpenSource/source.extension.vsixmanifest
@@ -29,5 +29,7 @@
+
+
\ No newline at end of file
diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
index c0a6d9798ca..39544c4d460 100644
--- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
+++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
@@ -5,6 +5,7 @@
..\..\..\srcFSharptrue
+ v4.6
@@ -23,10 +24,12 @@
- false
+
+
+
@@ -50,6 +53,7 @@
+
@@ -64,6 +68,30 @@
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.Composition.$(MicrosoftCompositionVersion)\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll
+
+
+ $(FSharpSourcesRoot)\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\dotnet\System.Collections.Immutable.dll
+
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.CodeAnalysis.Common.$(RoslynVersion)\lib\net45\Microsoft.CodeAnalysis.dll
+
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.$(RoslynVersion)\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll
+
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.CodeAnalysis.Features.$(RoslynVersion)\lib\net45\Microsoft.CodeAnalysis.Features.dll
+
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.CodeAnalysis.EditorFeatures.$(RoslynVersion)\lib\net46\Microsoft.CodeAnalysis.EditorFeatures.dll
+
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.CodeAnalysis.EditorFeatures.Text.$(RoslynVersion)\lib\net46\Microsoft.CodeAnalysis.EditorFeatures.Text.dll
+
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.VisualStudio.LanguageServices.$(RoslynVersion)\lib\net46\Microsoft.VisualStudio.LanguageServices.dll
+
\ No newline at end of file
diff --git a/vsintegration/src/FSharp.Editor/FSharpContentType.fs b/vsintegration/src/FSharp.Editor/FSharpContentType.fs
new file mode 100644
index 00000000000..849f1587fc9
--- /dev/null
+++ b/vsintegration/src/FSharp.Editor/FSharpContentType.fs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.Editor
+
+open System.ComponentModel.Composition
+
+open Microsoft.CodeAnalysis.Editor
+open Microsoft.VisualStudio.Utilities
+
+open Microsoft.VisualStudio.FSharp.LanguageService
+
+module FSharpStaticTypeDefinitions =
+ []
+ []
+ []
+ let FSharpContentTypeDefinition = ContentTypeDefinition()
+
+[]
+type FSharpContentType [](contentTypeRegistry : IContentTypeRegistryService) =
+ member this.contentTypeRegistryService = contentTypeRegistry
+
+ interface IContentTypeLanguageService with
+ member this.GetDefaultContentType() =
+ this.contentTypeRegistryService.GetContentType(FSharpCommonConstants.FSharpContentTypeName);
\ No newline at end of file
diff --git a/vsintegration/src/FSharp.Editor/FSharpProjectSiteService.fs b/vsintegration/src/FSharp.Editor/FSharpProjectSiteService.fs
new file mode 100644
index 00000000000..acd1e712205
--- /dev/null
+++ b/vsintegration/src/FSharp.Editor/FSharpProjectSiteService.fs
@@ -0,0 +1,31 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.Editor
+
+open System.Composition
+
+open Microsoft.CodeAnalysis
+open Microsoft.CodeAnalysis.Host
+open Microsoft.CodeAnalysis.Host.Mef
+
+open Microsoft.VisualStudio.FSharp.LanguageService
+open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
+
+// Currently the CompilationOptions type in Roslyn is sealed and there's no way to set the compilation options for a project.
+// There's no property bag on a project either. So this service is a means to get the host project for a given Roslyn project
+// so that extra F# specific information can be stored on the host project.
+// Note that the FSharpProject is available only through the VS Workspace although we might call this service from projects of
+// some other workspace like the PreviewWorkspace.
+type internal IHostProjectService =
+ inherit IWorkspaceService
+
+ abstract member GetHostProject : id : ProjectId -> FSharpProjectSite
+
+[, ServiceLayer.Default); Shared>]
+type internal FSharpProjectSiteService [] (vsWorkspace : VisualStudioWorkspaceImpl) =
+ interface IWorkspaceServiceFactory with
+ member this.CreateService(_) = upcast this
+
+ interface IHostProjectService with
+ member this.GetHostProject(id:ProjectId) =
+ downcast vsWorkspace.GetHostProject(id)
\ No newline at end of file
diff --git a/vsintegration/src/FSharp.Editor/extension.vsixmanifest b/vsintegration/src/FSharp.Editor/extension.vsixmanifest
index ec8e9ea37d5..a38c05d0066 100644
--- a/vsintegration/src/FSharp.Editor/extension.vsixmanifest
+++ b/vsintegration/src/FSharp.Editor/extension.vsixmanifest
@@ -1,24 +1,23 @@
-
-
- Microsoft Visual FSharp Editor Extensions
- Microsoft Corporation
- 14.0
- Microsoft Visual FSharp Editor Extensions
- 1033
-
-
- Pro
- VWDExpress
- WDExpress
-
-
-
+
+
+
+ Microsoft Visual FSharp Editor Extensions
+ Microsoft Visual FSharp Editor Extensions
+
+
+
+
+
+ true
-
-
-
- FSharp.Editor.dll
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vsintegration/src/FSharp.LanguageService/FSharp.LanguageService.fsproj b/vsintegration/src/FSharp.LanguageService/FSharp.LanguageService.fsproj
index f0aeeeca0a6..e0b5e612e84 100644
--- a/vsintegration/src/FSharp.LanguageService/FSharp.LanguageService.fsproj
+++ b/vsintegration/src/FSharp.LanguageService/FSharp.LanguageService.fsproj
@@ -5,6 +5,7 @@
..\..\..\srcFSharptrue
+ v4.6Debug
@@ -25,6 +26,7 @@
+
@@ -37,8 +39,8 @@
+
-
@@ -86,6 +88,21 @@
+
+ $(FSharpSourcesRoot)\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\dotnet\System.Collections.Immutable.dll
+
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.CodeAnalysis.Common.$(RoslynVersion)\lib\net45\Microsoft.CodeAnalysis.dll
+
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.$(RoslynVersion)\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll
+
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.CodeAnalysis.Features.$(RoslynVersion)\lib\net45\Microsoft.CodeAnalysis.Features.dll
+
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.VisualStudio.LanguageServices.$(RoslynVersion)\lib\net46\Microsoft.VisualStudio.LanguageServices.dll
+ {DED3BBD7-53F4-428A-8C9F-27968E768605}FSharp.Core
diff --git a/vsintegration/src/FSharp.LanguageService/FSharpCommonConstants.fs b/vsintegration/src/FSharp.LanguageService/FSharpCommonConstants.fs
new file mode 100644
index 00000000000..b1133e186eb
--- /dev/null
+++ b/vsintegration/src/FSharp.LanguageService/FSharpCommonConstants.fs
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.LanguageService
+
+open System
+open System.Configuration
+open System.Diagnostics
+
+module internal FSharpCommonConstants =
+ []
+ let packageGuidString = "871D2A70-12A2-4e42-9440-425DD92A4116"
+ []
+ let languageServiceGuidString = "BC6DD5A5-D4D6-4dab-A00D-A51242DBAF1B"
+ []
+ let editorFactoryGuidString = "4EB7CCB7-4336-4FFD-B12B-396E9FD079A9"
+ []
+ let codePageEditorFactoryGuidString = "82A16493-EF43-47E0-B42D-D87BAAB5335D"
+ []
+ let svsSettingsPersistenceManagerGuidString = "9B164E40-C3A2-4363-9BC5-EB4039DEF653"
+ []
+ let FSharpLanguageName = "F#"
+ []
+ let FSharpContentTypeName = "F#"
+ []
+ let FSharpLanguageServiceCallbackName = "F# Language Service"
diff --git a/vsintegration/src/FSharp.LanguageService/FSharpLanguageService.fs b/vsintegration/src/FSharp.LanguageService/FSharpLanguageService.fs
index 54b2110fbd5..ec6522776fc 100644
--- a/vsintegration/src/FSharp.LanguageService/FSharpLanguageService.fs
+++ b/vsintegration/src/FSharp.LanguageService/FSharpLanguageService.fs
@@ -3,618 +3,120 @@
namespace Microsoft.VisualStudio.FSharp.LanguageService
open System
-open System.IO
open System.Collections.Generic
-open System.Configuration
-open System.Globalization
open System.Runtime.InteropServices
-open Microsoft.VisualStudio
-open Microsoft.VisualStudio.Shell
-open Microsoft.VisualStudio.Shell.Interop
-open Microsoft.VisualStudio.TextManager.Interop
-open Microsoft.VisualStudio.Text
-open Microsoft.VisualStudio.OLE.Interop
-open Microsoft.FSharp.Compiler
-open Microsoft.FSharp.Compiler.SourceCodeServices
-
-// This is the list of known owners of callbacks that may register themselves.
-// Consumers not in this list should use a GUID our some other strongly unique key string
-module internal KnownAdviseProjectSiteChangesCallbackOwners =
- let LanguageService = "F# Language Service"
-
-module internal FSharpCommonConstants =
- []
- let languageServiceGuidString = "BC6DD5A5-D4D6-4dab-A00D-A51242DBAF1B"
-
-
-module internal FSharpConstants =
- let fsharpLanguageName = "F#"
-
- // These are the IDs from fslangservice.dll
- let packageGuidString = "871D2A70-12A2-4e42-9440-425DD92A4116"
- []
- let languageServiceGuidString = FSharpCommonConstants.languageServiceGuidString
-
- // These are the IDs from the Python sample:
- let intellisenseProviderGuidString = "8b1807ea-d222-4765-afa8-c092d480e451"
-
- // These are the entries from fslangservice.dll
- let PLKMinEdition = "standard"
- let PLKCompanyName = "Microsoft" // "Microsoft Corporation"
- let PLKProductName = "f#" // "Visual Studio Integration of FSharp Language Service"
- let PLKProductVersion = "1.0"
- let PLKResourceID = 1s
- let enableLanguageService = "fsharp-language-service-enabled"
+open Microsoft.FSharp.Compiler.SourceCodeServices
-
-/// This class defines capabilities of the language service.
-/// CodeSense = true\false, for example
-type internal FSharpLanguagePreferences(site, langSvc, name) =
- inherit LanguagePreferences(site, langSvc, name)
-
-// Container class that delays loading of FSharp.Compiler.dll compiler types until they're actually needed
-type internal FSharpCheckerContainer(checker) =
- member this.FSharpChecker = checker
-
-/// LanguageService state.
-type internal FSharpLanguageServiceTestable() as this =
- static let colorizerGuid = new Guid("{A2976312-7D71-4BB4-A5F8-66A08EBF46C8}") // Guid for colorizwed user data on IVsTextBuffer
- let mutable checkerContainerOpt : FSharpCheckerContainer option = None
- let mutable artifacts : ProjectSitesAndFiles option = None
- let mutable serviceProvider : System.IServiceProvider option = None
- let mutable preferences : LanguagePreferences option = None
- let mutable documentationBuilder : IDocumentationBuilder option = None
- let mutable sourceFactory : (IVsTextLines -> IFSharpSource) option = None
- let mutable dirtyForTypeCheckFiles : Set = Set.empty
- let mutable isInitialized = false
- let mutable unhooked = false
- let getColorizer (view:IVsTextView) =
- let buffer = Com.ThrowOnFailure1(view.GetBuffer())
- this.GetColorizer(buffer)
-
- let bgRequests = new FSharpLanguageServiceBackgroundRequests(getColorizer,(fun () -> this.FSharpChecker),(fun () -> this.ProjectSitesAndFiles),(fun () -> this.ServiceProvider),(fun () -> this.DocumentationBuilder))
-
- member this.FSharpChecker =
- if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
- if not this.IsInitialized then raise Error.UseOfUninitializedLanguageServiceState
- checkerContainerOpt.Value.FSharpChecker
-
- member this.ServiceProvider =
- if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
- if not this.IsInitialized then raise Error.UseOfUninitializedLanguageServiceState
- serviceProvider.Value
+open Microsoft.CodeAnalysis
+open Microsoft.VisualStudio
+open Microsoft.VisualStudio.LanguageServices
+open Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService
+open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
+open Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelliSense
+open Microsoft.VisualStudio.LanguageServices.Implementation
+open Microsoft.VisualStudio.Shell
+open Microsoft.VisualStudio.Shell.Interop
- member this.ProjectSitesAndFiles =
- if not this.IsInitialized then raise Error.UseOfUninitializedLanguageServiceState
- artifacts.Value
-
- member this.Preferences =
- if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
- if not this.IsInitialized then raise Error.UseOfUninitializedLanguageServiceState
- preferences.Value
-
- member this.SourceFactory =
- if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
- if not this.IsInitialized then raise Error.UseOfUninitializedLanguageServiceState
- sourceFactory.Value
-
- member this.IsInitialized = isInitialized
- member this.Unhooked = unhooked
- member this.DocumentationBuilder = documentationBuilder.Value
-
- /// Handle late intialization pieces
- member this.Initialize (sp, dp, prefs, sourceFact) =
- if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
- artifacts <- Some (ProjectSitesAndFiles())
- let checker = FSharpChecker.Create()
- checker.BeforeBackgroundFileCheck.Add (fun filename -> UIThread.Run(fun () -> this.NotifyFileTypeCheckStateIsDirty(filename)))
- checkerContainerOpt <- Some (FSharpCheckerContainer checker)
- serviceProvider <- Some sp
- isInitialized <- true
- unhooked <- false
- documentationBuilder <- Some dp
- preferences <- Some prefs
- sourceFactory <- Some sourceFact
+// Workaround to access non-public settings persistence type.
+// GetService( ) with this will work as long as the GUID matches the real type.
+[]
+type internal SVsSettingsPersistenceManager = class end
-
- member this.NotifyFileTypeCheckStateIsDirty(filename) =
- dirtyForTypeCheckFiles <- dirtyForTypeCheckFiles.Add filename
+[]
+type internal FSharpLanguageService(package : FSharpPackage) =
+ inherit AbstractLanguageService(package)
- /// Clear all language service caches and finalize all transient references to compiler objects
- member this.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() =
- if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
- if this.IsInitialized then
- this.FSharpChecker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients()
+ override this.ContentTypeName = FSharpCommonConstants.FSharpContentTypeName
+ override this.LanguageName = FSharpCommonConstants.FSharpLanguageName
+ override this.RoslynLanguageName = FSharpCommonConstants.FSharpLanguageName
- /// Unhook the object. These are the held resources that need to be disposed.
- member this.Unhook() =
- if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
- if this.IsInitialized then
- // Dispose the preferences.
- if this.Preferences <> null then this.Preferences.Dispose()
- // Stop the background compile.
- // here we refer to checkerContainerOpt directly to avoid triggering its creation
- match checkerContainerOpt with
- | Some container ->
- let checker = container.FSharpChecker
- checker.StopBackgroundCompile()
- checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients()
- | None -> ()
-
- checkerContainerOpt <- None
- artifacts <- None
- preferences <- None
- documentationBuilder <- None
- unhooked <- true
- sourceFactory <- None
- serviceProvider <- None
-
- /// Respond to project settings changes
- member this.OnProjectSettingsChanged(site:IProjectSite) =
- // The project may have changed its references. These would be represented as 'dependency files' of each source file. Each source file will eventually start listening
- // for changes to those dependencies, at which point we'll get OnDependencyFileCreateOrDelete notifications. Until then, though, we just 'make a note' that this project is out of date.
- bgRequests.AddOutOfDateProjectFileName(site.ProjectFileName())
- for filename in site.SourceFilesOnDisk() do
- let rdt = this.ServiceProvider.RunningDocumentTable
- match this.ProjectSitesAndFiles.TryGetSourceOfFile(rdt,filename) with
- | Some source ->
- source.RecolorizeWholeFile()
- source.RecordChangeToView()
- | None -> ()
+ override this.LanguageServiceId = new Guid(FSharpCommonConstants.languageServiceGuidString)
+ override this.DebuggerLanguageId = DebuggerEnvironment.GetLanguageID()
- /// Respond to project being cleaned/rebuilt (any live type providers in the project should be refreshed)
- member this.OnProjectCleaned(projectSite:IProjectSite) =
- let checkOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(projectSite, "")
- this.FSharpChecker.NotifyProjectCleaned(checkOptions)
+ override this.CreateContext(_,_,_,_,_) = raise(System.NotImplementedException())
- member this.OnActiveViewChanged(textView) =
- bgRequests.OnActiveViewChanged(textView)
+ override this.SetupNewTextView(view) =
+ base.SetupNewTextView(view)
+ let workspace = this.Package.ComponentModel.GetService();
+ let sp = new ServiceProvider(this.SystemServiceProvider.GetService())
- member this.BackgroundRequests = bgRequests
-
- /// Unittestable complement to LanguageServce.CreateSource
- member this.CreateSource(buffer:IVsTextLines) : IFSharpSource =
-
- // Each time a source is created, also verify that the IProjectSite has been initialized to listen to changes to the project.
- // We can't listen to OnProjectLoaded because the language service is not guaranteed to be loaded when this is called.
+ // Ensure that we have a project in the workspace for this document.
+ let (_, buffer) = view.GetBuffer()
let filename = VsTextLines.GetFilename buffer
- let rdt = this.ServiceProvider.RunningDocumentTable
- let result = VsRunningDocumentTable.FindDocumentWithoutLocking(rdt,filename)
- match result with
- | Some(hier,_) ->
- match hier with
+ let result = VsRunningDocumentTable.FindDocumentWithoutLocking(sp.RunningDocumentTable,filename)
+ match result with
+ | Some (hier, _) ->
+ match hier with
| :? IProvideProjectSite as siteProvider ->
let site = siteProvider.GetProjectSite()
- site.AdviseProjectSiteChanges(KnownAdviseProjectSiteChangesCallbackOwners.LanguageService,
- new AdviseProjectSiteChanges(fun () -> this.OnProjectSettingsChanged(site)))
- site.AdviseProjectSiteCleaned(KnownAdviseProjectSiteChangesCallbackOwners.LanguageService,
- new AdviseProjectSiteChanges(fun () -> this.OnProjectCleaned(site)))
- | _ ->
- // This can happen when the file is in a solution folder or in, say, a C# project.
- ()
- | _ ->
- // This can happen when renaming a file from a different language service into .fs or fsx.
- // This naturally won't have an associated project.
- ()
-
- // Create the source and register file change callbacks there.
- let source = this.SourceFactory(buffer)
- this.ProjectSitesAndFiles.SetSource(buffer, source)
- source
+ let projectFileName = site.ProjectFileName()
+ let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectFileName)
+ if obj.ReferenceEquals(workspace.ProjectTracker.GetProject(projectId), null) then
+ let projectSite = new FSharpProjectSite(hier, this.SystemServiceProvider, workspace, projectFileName);
+ projectSite.Initialize(hier, site)
+ | _ -> ()
+ | _ -> ()
+
+and []
+ internal FSharpEditorFactory(package : FSharpPackage) =
+ inherit AbstractEditorFactory(package)
+
+ override this.ContentTypeName = FSharpCommonConstants.FSharpContentTypeName
+ override this.GetFormattedTextChanges(_, _, _, _) = upcast Array.empty
- // For each change in dependency files, notify the language service of the change and propagate the update
- interface IDependencyFileChangeNotify with
- member this.DependencyFileCreated projectSite =
- // Invalidate the configuration if we notice any add for any DependencyFiles
- let checkOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(projectSite, "")
- this.FSharpChecker.InvalidateConfiguration(checkOptions)
-
- member this.DependencyFileChanged (filename) =
- this.NotifyFileTypeCheckStateIsDirty filename
-
-
- /// Do OnIdle processing for the whole language service. dirtyForTypeCheckFiles can be set by events
- /// raised on the background compilation thread.
- member this.OnIdle() =
- for file in dirtyForTypeCheckFiles do
- let rdt = this.ServiceProvider.RunningDocumentTable
- match this.ProjectSitesAndFiles.TryGetSourceOfFile(rdt, file) with
- | Some source -> source.RecordChangeToView()
- | None -> ()
- dirtyForTypeCheckFiles <- Set.empty
-
-
- /// Remove a colorizer.
- member this.CloseColorizer(colorizer:FSharpColorizer) =
- let buffer = colorizer.Buffer
- let mutable guid = colorizerGuid
- (buffer :?> IVsUserData).SetData(&guid, null) |> ErrorHandler.ThrowOnFailure |> ignore
+and []
+ internal FSharpCodePageEditorFactory(editorFactory: FSharpEditorFactory) =
+ inherit AbstractCodePageEditorFactory(editorFactory)
- /// Get a colorizer for a particular buffer.
- member this.GetColorizer(buffer:IVsTextLines) : FSharpColorizer =
- let mutable guid = colorizerGuid
- let mutable colorizerObj = null
-
- (buffer :?> IVsUserData).GetData(&guid, &colorizerObj) |> ignore
- match colorizerObj with
- | null ->
- let scanner =
- new FSharpScanner(fun source ->
- // Note: in theory, the next few lines do not need to be recomputed every line. Instead we could just cache the tokenizer
- // and only update it when e.g. the project system notifies us there is an important change (e.g. a file rename, etc).
- // In practice we have been there, and always screwed up some non-unit-tested/testable corner-cases.
- // So this is not ideal from a perf perspective, but it is easy to reason about the correctness.
- let filename = VsTextLines.GetFilename buffer
- let rdt = this.ServiceProvider.RunningDocumentTable
- let defines = this.ProjectSitesAndFiles.GetDefinesForFile(rdt, filename)
- let sourceTokenizer = FSharpSourceTokenizer(defines,filename)
- sourceTokenizer.CreateLineTokenizer(source))
-
- let colorizer = new FSharpColorizer(this.CloseColorizer, buffer, scanner)
- (buffer :?> IVsUserData).SetData(&guid, colorizer) |> ErrorHandler.ThrowOnFailure |> ignore
- colorizer
- | _ -> colorizerObj :?> FSharpColorizer
+and []
+ internal FSharpPackage() =
+ inherit AbstractPackage()
- /// Block until the background compile finishes.
- //
- // This is for unit testing only
- member this.WaitForBackgroundCompile() =
- this.FSharpChecker.WaitForBackgroundCompile()
+ override this.RoslynLanguageName = FSharpCommonConstants.FSharpLanguageName
-module internal VsConstants =
- let guidStdEditor = new Guid("9ADF33D0-8AAD-11D0-B606-00A0C922E851")
- let guidCodeCloneProvider = new Guid("38fd587e-d4b7-4030-9a95-806ff0d5c2c6")
+ override this.Initialize() =
+ base.Initialize()
+ this.EstablishDefaultSettingsIfMissing()
- let cmdidGotoDecl = 936u // "Go To Declaration"
- let cmdidGotoRef = 1107u // "Go To Reference"
+ override this.CreateWorkspace() = this.ComponentModel.GetService()
- let IDM_VS_EDITOR_CSCD_OUTLINING_MENU = 773u // "Outlining"
- let ECMD_OUTLN_HIDE_SELECTION = 128u // "Hide Selection" -
- let ECMD_OUTLN_TOGGLE_CURRENT = 129u // "Toggle Outlining Expansion" -
- let ECMD_OUTLN_TOGGLE_ALL = 130u // "Toggle All Outlining"
- let ECMD_OUTLN_STOP_HIDING_ALL = 131u // "Stop Outlining"
- let ECMD_OUTLN_STOP_HIDING_CURRENT = 132u // "Stop Hiding Current"
-
-type private QueryStatusResult =
- | NOTSUPPORTED = 0
- | SUPPORTED = 1
- | ENABLED = 2
- | LATCHED = 4
- | NINCHED = 8
- | INVISIBLE = 16
-
-type internal FSharpViewFilter(mgr:CodeWindowManager,view:IVsTextView) =
- inherit ViewFilter(mgr,view)
-
- override this.Dispose() = base.Dispose()
-
- member this.IsSupportedCommand(guidCmdGroup:byref,cmd:uint32) =
- if guidCmdGroup = VsMenus.guidStandardCommandSet97 && (cmd = VsConstants.cmdidGotoDecl || cmd = VsConstants.cmdidGotoRef) then false
- elif guidCmdGroup = VsConstants.guidCodeCloneProvider then false // disable commands for CodeClone package
- else
- // These are all the menu options in the "Outlining" cascading menu. We need to disable all the individual
- // items to disable the cascading menu. QueryCommandStatus does not get called for the cascading menu itself.
- assert((guidCmdGroup = VsConstants.guidStdEditor && cmd = VsConstants.IDM_VS_EDITOR_CSCD_OUTLINING_MENU) = false)
- if guidCmdGroup = VsMenus.guidStandardCommandSet2K && (cmd = VsConstants.ECMD_OUTLN_HIDE_SELECTION ||
- cmd = VsConstants.ECMD_OUTLN_TOGGLE_CURRENT ||
- cmd = VsConstants.ECMD_OUTLN_TOGGLE_ALL ||
- cmd = VsConstants.ECMD_OUTLN_STOP_HIDING_ALL ||
- cmd = VsConstants.ECMD_OUTLN_STOP_HIDING_CURRENT) then false
- else true
-
- override this.QueryCommandStatus(guidCmdGroup:byref,cmd:uint32) =
- if this.IsSupportedCommand(&guidCmdGroup,cmd) then
- base.QueryCommandStatus(&guidCmdGroup,cmd)
- else
- // Hide the menu item. Just returning QueryStatusResult.NOTSUPPORTED does not work
- QueryStatusResult.INVISIBLE ||| QueryStatusResult.SUPPORTED |> int
+ override this.CreateLanguageService() = new FSharpLanguageService(this)
+ override this.CreateEditorFactories() =
+ // Disabling editor factories until fully implemented
-[]
-type internal FSharpLanguageService() as fls =
- inherit LanguageService()
-
- let ls = FSharpLanguageServiceTestable()
- let mutable rdtCookie = VSConstants.VSCOOKIE_NIL
-
- let thisAssembly = typeof.Assembly
- let resources = lazy (new System.Resources.ResourceManager("VSPackage", thisAssembly))
- let GetString(name:string) = resources.Force().GetString(name, CultureInfo.CurrentUICulture)
+ // let editorFactory = new FSharpEditorFactory(this)
+ // let codePageEditorFactory = new FSharpCodePageEditorFactory(editorFactory)
- let navigation = FSharpNavigationController()
+ [|
+ // editorFactory :> IVsEditorFactory;
+ // codePageEditorFactory :> IVsEditorFactory;
+ |] :> seq
- let formatFilterList = lazy(
- let fsFile = GetString("FSharpFile")
- let fsInterfaceFile = GetString("FSharpInterfaceFile")
- let fsxFile = GetString("FSXFile")
- let fsScriptFile = GetString("FSharpScriptFile")
- let result = sprintf "%s|*.fs\n%s|*.fsi\n%s|*.fsx\n%s|*.fsscript"
- fsFile fsInterfaceFile fsxFile fsScriptFile
- result)
+ override this.RegisterMiscellaneousFilesWorkspaceInformation(_) = ()
- // This array contains the definition of the colorable items provided by this
- // language service.
- let colorableItems = [|
- // See e.g. the TokenColor type defined in Scanner.cs. Position 0 is implicit and always means "Plain Text".
- // The next 5 items in this list MUST be these default items in this order:
- new FSharpColorableItem("Keyword", lazy (GetString("Keyword")), COLORINDEX.CI_BLUE, COLORINDEX.CI_USERTEXT_BK)
- new FSharpColorableItem("Comment", lazy (GetString("Comment")), COLORINDEX.CI_DARKGREEN, COLORINDEX.CI_USERTEXT_BK)
- new FSharpColorableItem("Identifier", lazy (GetString("Identifier")), COLORINDEX.CI_USERTEXT_FG, COLORINDEX.CI_USERTEXT_BK)
- new FSharpColorableItem("String", lazy (GetString("String")), COLORINDEX.CI_MAROON, COLORINDEX.CI_USERTEXT_BK)
- new FSharpColorableItem("Number", lazy (GetString("Number")), COLORINDEX.CI_USERTEXT_FG, COLORINDEX.CI_USERTEXT_BK)
- // User-defined color classes go here:
- new FSharpColorableItem("Excluded Code", lazy (GetString("ExcludedCode")), COLORINDEX.CI_DARKGRAY, COLORINDEX.CI_USERTEXT_BK)
- new FSharpColorableItem("Preprocessor Keyword", lazy (GetString("PreprocessorKeyword")), COLORINDEX.CI_BLUE, COLORINDEX.CI_USERTEXT_BK)
- new FSharpColorableItem("Operator", lazy (GetString("Operator")), COLORINDEX.CI_USERTEXT_FG, COLORINDEX.CI_USERTEXT_BK)
- |]
-
- let sourceFactory(buffer:IVsTextLines) =
- let vsFileWatch = fls.GetService(typeof) :?> IVsFileChangeEx
- Source.CreateSource(fls, buffer, fls.GetColorizer(buffer), vsFileWatch, ls :> IDependencyFileChangeNotify, (fun () -> ls.FSharpChecker))
-
- let refreshUI() =
- let uiShell = fls.Site.GetService()
- if (uiShell <> null) then
- uiShell.UpdateCommandUI(0) |> ignore
-
-
- /// Initialize the language service
- override fls.Initialize() =
- if not ls.IsInitialized then
- let preferences = new FSharpLanguagePreferences(fls.Site, (typeof).GUID, FSharpConstants.fsharpLanguageName)
- preferences.Init() // Reads preferences from the VS registry.
- preferences.MaxErrorMessages <- 1000
-
- let serviceProvider = fls.Site
- let docBuilder = XmlDocumentation.CreateDocumentationBuilder(serviceProvider.XmlService, serviceProvider.DTE)
-
- ls.Initialize(serviceProvider, docBuilder, preferences, sourceFactory)
-
- rdtCookie <- (Com.ThrowOnFailure1 (serviceProvider.RunningDocumentTable.AdviseRunningDocTableEvents (fls:>IVsRunningDocTableEvents)))
-
-
- override fls.Dispose() =
- try
- try
- if rdtCookie <> VSConstants.VSCOOKIE_NIL then
- let rdt = fls.Site.RunningDocumentTable
- Com.ThrowOnFailure0 (rdt.UnadviseRunningDocTableEvents rdtCookie)
- finally
- if ls.IsInitialized then
- ls.Unhook()
- finally
- base.Dispose()
-
- member fls.Core = ls
-
- // -----------------------------------------------------------------------
- // Implement IVsLanguageInfo
-
- interface IVsLanguageInfo with
- /// Allows a language to add adornments to a code editor.
- member this.GetCodeWindowManager(codeWindow, mgr) =
- fls.Initialize();
- let mutable buffer = null;
- NativeMethods.ThrowOnFailure(codeWindow.GetBuffer(&buffer)) |> ignore;
- // see if we already have a Source object.
- let source =
- match this.GetSource(buffer) with
- | null ->
- let s = ls.CreateSource(buffer) :?> ISource
- this.sources.Add(s) |> ignore;
- s
- | s -> s
-
- mgr <- this.CreateCodeWindowManager(codeWindow, source);
- NativeMethods.S_OK;
-
- /// Returns the colorizer.
- member this.GetColorizer(buffer, result) =
- result <- this.GetColorizer(buffer)
- NativeMethods.S_OK
-
- /// Returns the file extensions belonging to this language.
- member this.GetFileExtensions(extensions) =
- extensions <- ""
- NativeMethods.S_OK
-
- member this.GetLanguageName(name) =
- name <- FSharpConstants.fsharpLanguageName
- NativeMethods.S_OK
-
- // -----------------------------------------------------------------------
- // Implement LanguageService base methods from the C# code
-
- override fls.OnActiveViewChanged(textView) =
- base.OnActiveViewChanged(textView)
- ls.OnActiveViewChanged(textView)
- if navigation.EnableNavBar || navigation.EnableRegions then
- match fls.GetSource(textView) with
- | null -> ()
- | source -> ls.BackgroundRequests.TriggerParseFile(textView, source) |> ignore
-
-
- // Provides the index to the filter matching the extension of the file passed in.
- override fls.CurFileExtensionFormat(filename) =
- // These indexes match the "GetFormatFilterList" function
- match Path.GetExtension(filename) with
- | ".fs" -> 0
- | ".ml" -> 1
- | ".fsi" -> 2
- | ".mli" -> 3
- | ".fsx" -> 4
- | ".fsscript" -> 5
- | _ -> -1
-
- /// Provides the list of available extensions for Save As.
- /// The following default filter string is automatically added by Visual Studio:
- /// "All Files (*.*)\n*.*\nText Files (*.txt)\n*.txt\n"
- override fls.GetFormatFilterList() =
- formatFilterList.Value
-
- // This seems to be called by codeWinMan.OnNewView(textView) to install a ViewFilter on the TextView.
- override this.CreateViewFilter(mgr:CodeWindowManager,newView:IVsTextView) = new FSharpViewFilter(mgr,newView) :> ViewFilter
-
- override fls.GetLanguagePreferences() = ls.Preferences
-
- override fls.CreateBackgroundRequest(line, col, info, sourceText, snapshot, methodTipMiscellany, fname, reason, view, sink, source, timestamp, synchronous) =
- ls.BackgroundRequests.CreateBackgroundRequest(line, col, info, sourceText, snapshot, methodTipMiscellany, fname,reason, view,sink, source, timestamp, synchronous) :> BackgroundRequest
-
- /// Handle an incoming request to analyze a file.
- ///
- /// Executed either on the UI thread (for req.IsSynchronous) or the background request thread.
- override fls.ExecuteBackgroundRequest(req:BackgroundRequest) =
- ls.BackgroundRequests.ExecuteBackgroundRequest(req :?> FSharpBackgroundRequest, req.Source :?> IFSharpSource)
-
- // Check if we can shortcut executing the background request and just fill in the latest
- // cached scope for the active view from this.service.RecentFullTypeCheckResults.
- //
- // THIS MUST ONLY RETURN TRUE IF ---> ExecuteBackgroundRequest is equivalent to fetching a recent,
- // perhaps out-of-date scope.
- override fls.IsRecentScopeSufficientForBackgroundRequest(reason) =
- ls.BackgroundRequests.IsRecentScopeSufficientForBackgroundRequest(reason)
-
- // This is called on the UI thread after fresh full typecheck results are available
- override fls.OnParseFileOrCheckFileComplete( req:BackgroundRequest) =
- if (req <> null && req.Source <> null && not req.Source.IsClosed) then
- fls.SetUserContextDirty(req.FileName)
- refreshUI()
- ls.BackgroundRequests.OnParseFileOrCheckFileComplete(req, navigation.EnableRegions, fls.LastActiveTextView)
-
- override fls.GetColorizer(buffer) =
- fls.Initialize()
- ls.GetColorizer(buffer) :> Colorizer
-
-
- override fls.CreateDropDownHelper(_view) =
- if navigation.EnableNavBar then
- (new FSharpNavigationBars(fls, fun () -> ls.BackgroundRequests.NavigationBarAndRegionInfo)) :> TypeAndMemberDropdownBars
- else null
-
- /// Do OnIdle processing
- override fls.OnIdle(periodic, mgr : IOleComponentManager) =
- try
- let r = base.OnIdle(periodic, mgr)
- ls.OnIdle()
- r
- with e->
- Assert.Exception(e)
- reraise()
-
- // -----------------------------------------------------------------------
- // Implement IVsLanguageDebugInfo
-
- /// This is used to return the expression evaluator language to the debugger
- interface IVsLanguageDebugInfo with
- // Returns the corresponding debugger back-end "language ID".
- member fls.GetLanguageID(_buffer,_line, _col, langId) =
- langId <- DebuggerEnvironment.GetLanguageID()
- VSConstants.S_OK
-
- // Deprecated. Do not use.
- member fls.GetLocationOfName(_name, pbstrMkDoc, _spans) =
- pbstrMkDoc <- null
- NativeMethods.E_NOTIMPL
-
- // Generates a name for the given location in the file.
- member fls.GetNameOfLocation(_buffer, _line, _col, name, lineOffset) =
- name <- null;
- lineOffset <- 0;
- NativeMethods.S_OK;
-
- // Generates proximity expressions, used to populate the "Autos" window
- member fls.GetProximityExpressions(_buffer, _line, _col, _cLines, ppEnum) =
- ppEnum <- null
- NativeMethods.S_FALSE
-
- // Returns whether the location contains code that is mapped to another document, for example, client-side script code.
- member fls.IsMappedLocation(_buffer, _line, _col) =
- NativeMethods.S_FALSE
-
- // Disambiguates the given name, providing non-ambiguous names for all entities that "match" the name.
- member fls.ResolveName(_name, _flags, ppNames) =
- ppNames <- null
- NativeMethods.E_NOTIMPL
-
- // Validates the given position as a place to set a breakpoint.
- member fls.ValidateBreakpointLocation(buffer:IVsTextBuffer, line, col, pCodeSpan:TextSpan[]) =
- let result =
- if (pCodeSpan <> null) && (pCodeSpan.Length > 0) && (buffer :? IVsTextLines) then
- let syncOk =
- let view = fls.LastActiveTextView
- view <> null &&
- let source = fls.GetSource(view)
- source <> null &&
- ls.BackgroundRequests.TrySynchronizeParseFileInformation(view, source, millisecondsTimeout = 100)
- let lineText = VsTextLines.LineText (buffer :?> IVsTextLines) line
- let firstNonWhitespace = lineText.Length - (lineText.TrimStart [| ' '; '\t' |]).Length
- let lastNonWhitespace = (lineText.TrimEnd [| ' '; '\t' |]).Length
- // If the column is before the range of text then zap it to the text
- // If the column is after the range of text then zap it to the _start_ of the text (like C#)
- let attempt1, haveScope =
- let col = if col > lastNonWhitespace || col < firstNonWhitespace then firstNonWhitespace else col
- match ls.BackgroundRequests.ParseFileResults with
- | Some parseResults ->
- match parseResults.ValidateBreakpointLocation(Range.Pos.fromZ line col) with
- | Some bpl -> Some (TextSpanOfRange bpl), true
- | None -> None, true
- | None ->
- None, false
- match attempt1 with
- | Some r -> Some r
- | None ->
- if syncOk || haveScope then
- None
- else
- // If we didn't sync OK AND we don't even have an ParseFileResults then just accept the whole line.
- // This is unfortunate but necessary.
- Some (TextSpan(iStartLine = line, iStartIndex = firstNonWhitespace, iEndLine = line, iEndIndex = lastNonWhitespace))
- else
- None
-
- match result with
- | Some span ->
- pCodeSpan.[0] <- span
- VSConstants.S_OK
- | None ->
- VSConstants.S_FALSE
-
- // -----------------------------------------------------------------------
- // Implement IVsProvideColorableItems
-
- interface IVsProvideColorableItems with
-
- member x.GetItemCount(count: int byref) =
- count <- colorableItems.Length
- VSConstants.S_OK
-
- member x.GetColorableItem(index, item: IVsColorableItem byref) =
- if (index < 1) || (index > colorableItems.Length) then
- VSConstants.E_INVALIDARG
- else
- item <- colorableItems.[index - 1]
- VSConstants.S_OK
-
- /// Respond to changes to documents in the Running Document Table.
- interface IVsRunningDocTableEvents with
- member this.OnAfterAttributeChange(_docCookie, _grfAttribs) = VSConstants.S_OK
- member this.OnAfterDocumentWindowHide(_docCookie, _frame) = VSConstants.S_OK
- member this.OnAfterFirstDocumentLock(_docCookie,_dwRDTLockType,_dwReadLocks,_dwEditLocks) = VSConstants.S_OK
- member this.OnAfterSave(_docCookie) = VSConstants.S_OK
- member this.OnBeforeDocumentWindowShow(_docCookie,_isFirstShow,_frame) = VSConstants.S_OK
- member this.OnBeforeLastDocumentUnlock(docCookie,_dwRDTLockType,dwReadLocksRemaining,dwEditLocksRemaining) =
- let rdt = this.Site.RunningDocumentTable
- let (_, _, _, _, file, _, _, unkdoc) = rdt.GetDocumentInfo docCookie // see here http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.interop.ivsrunningdocumenttable.getdocumentinfo(VS.80).aspx for info on the `GetDocumentInfo` results we're ignoring
- try
- if int dwReadLocksRemaining = 0 && int dwEditLocksRemaining = 0 then // check that this is there are no other read / edit locks
- if SourceFile.IsCompilable file then
- if IntPtr.Zero<>unkdoc then
- match Marshal.GetObjectForIUnknown(unkdoc) with
- | :? IVsTextLines as tl ->
- ls.ProjectSitesAndFiles.UnsetSource(tl)
- | _ -> ()
- finally
- if IntPtr.Zero <> unkdoc then Marshal.Release(unkdoc)|>ignore
- VSConstants.S_OK
-
+ /// ISettingsManager only implemented for VS 14.0+
+ /// In case custom VS profile settings for F# are not applied, explicitly set them here.
+ /// e.g. 'keep tabs' is the text editor default, but F# requires 'insert spaces'.
+ /// We specify our customizations in the General profile for VS, but we have found that in some cases,
+ /// those customizations are incorrectly ignored. So we take action if the setting has no current custom value.
+ member private this.EstablishDefaultSettingsIfMissing() =
+ #if !VS_VERSION_DEV12
+
+ let fsharpSpecificProfileSettings = [|
+ "TextEditor.F#.Insert Tabs", box false
+ "TextEditor.F#.Brace Completion", box true
+ "TextEditor.F#.Make URLs Hot", box false
+ "TextEditor.F#.Indent Style", box 1u |]
+
+ match this.GetService(typeof) with
+ | :? Microsoft.VisualStudio.Settings.ISettingsManager as settingsManager ->
+ for settingName,defaultValue in fsharpSpecificProfileSettings do
+ match settingsManager.TryGetValue(settingName) with
+ | Microsoft.VisualStudio.Settings.GetValueResult.Missing, _ ->
+ settingsManager.SetValueAsync(settingName, defaultValue, false) |> ignore
+ | _ -> ()
+ | _ -> ()
+
+ #endif
\ No newline at end of file
diff --git a/vsintegration/src/FSharp.LanguageService/FSharpPackage.fs b/vsintegration/src/FSharp.LanguageService/FSharpPackage.fs
deleted file mode 100644
index fb61e0e854a..00000000000
--- a/vsintegration/src/FSharp.LanguageService/FSharpPackage.fs
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-namespace Microsoft.VisualStudio.FSharp.LanguageService
-
-open System
-open System.Configuration
-open System.ComponentModel.Design
-open System.Runtime.InteropServices
-open Microsoft.VisualStudio
-open Microsoft.VisualStudio.Shell
-open Microsoft.VisualStudio.OLE.Interop
-
-
-// Workaround to access non-public settings persistence type.
-// GetService( ) with this will work as long as the GUID matches the real type.
-[]
-type internal SVsSettingsPersistenceManager = class end
-
-[]
-type internal FSharpPackage() as self =
- inherit Package()
-
- // In case the config file is incorrect, we silently recover and leave the feature enabled
- let enableLanguageService =
- try
- "false" <> ConfigurationManager.AppSettings.[FSharpConstants.enableLanguageService]
- with e ->
- System.Diagnostics.Debug.Assert
- (false, sprintf "Error while loading 'devenv.exe.config' configuration: %A" e)
- true
-
- let mutable componentID = 0u
-
- let CreateIfEnabled container serviceType =
- if enableLanguageService then
- self.CreateService(container,serviceType)
- else
- null
-
- let callback = new ServiceCreatorCallback(CreateIfEnabled)
-
- let mutable mgr : IOleComponentManager = null
-
-#if !VS_VERSION_DEV12
- let fsharpSpecificProfileSettings =
- [| "TextEditor.F#.Insert Tabs", box false
- "TextEditor.F#.Brace Completion", box true
- "TextEditor.F#.Make URLs Hot", box false
- "TextEditor.F#.Indent Style", box 1u |]
-#endif
-
- override self.Initialize() =
- UIThread.CaptureSynchronizationContext()
- self.EstablishDefaultSettingsIfMissing()
- (self :> IServiceContainer).AddService(typeof, callback, true)
- base.Initialize()
-
- /// In case custom VS profile settings for F# are not applied, explicitly set them here.
- /// e.g. 'keep tabs' is the text editor default, but F# requires 'insert spaces'.
- /// We specify our customizations in the General profile for VS, but we have found that in some cases
- /// those customizations are incorrectly ignored.
- member private this.EstablishDefaultSettingsIfMissing() =
-#if VS_VERSION_DEV12
- () // ISettingsManager only implemented for VS 14.0+
-#else
- match this.GetService(typeof) with
- | :? Microsoft.VisualStudio.Settings.ISettingsManager as settingsManager ->
- for settingName,defaultValue in fsharpSpecificProfileSettings do
- // Only take action if the setting has no current custom value
- // If cloud-synced settings have already been applied or the user has made an explicit change, do nothing
- match settingsManager.TryGetValue(settingName) with
- | Microsoft.VisualStudio.Settings.GetValueResult.Missing, _ ->
- settingsManager.SetValueAsync(settingName, defaultValue, false) |> ignore
- | _ -> ()
- | _ -> ()
-#endif
-
- member self.RegisterForIdleTime() =
- mgr <- (self.GetService(typeof) :?> IOleComponentManager)
- if (componentID = 0u && mgr <> null) then
- let crinfo = Array.zeroCreate(1)
- let mutable crinfo0 = crinfo.[0]
- crinfo0.cbSize <- Marshal.SizeOf(typeof) |> uint32
- crinfo0.grfcrf <- uint32 (_OLECRF.olecrfNeedIdleTime ||| _OLECRF.olecrfNeedPeriodicIdleTime)
- crinfo0.grfcadvf <- uint32 (_OLECADVF.olecadvfModal ||| _OLECADVF.olecadvfRedrawOff ||| _OLECADVF.olecadvfWarningsOff)
- crinfo0.uIdleTimeInterval <- 1000u
- crinfo.[0] <- crinfo0
- let componentID_out = ref componentID
- let _hr = mgr.FRegisterComponent(self, crinfo, componentID_out)
- componentID <- componentID_out.Value
- ()
-
- member self.CreateService(_container:IServiceContainer, serviceType:Type) =
- match serviceType with
- | x when x = typeof ->
- let language = new FSharpLanguageService()
- language.SetSite(self)
- language.Initialize()
- self.RegisterForIdleTime()
- box language
- | _ -> null
-
- override self.Dispose(disposing) =
- try
- if (componentID <> 0u) then
- begin match self.GetService(typeof) with
- | :? IOleComponentManager as mgr ->
- mgr.FRevokeComponent(componentID) |> ignore
- | _ -> ()
- end
- componentID <- 0u
- finally
- base.Dispose(disposing)
-
- interface IOleComponent with
-
- override x.FContinueMessageLoop(_uReason:uint32, _pvLoopData:IntPtr, _pMsgPeeked:MSG[]) =
- 1
-
- override x.FDoIdle(grfidlef:uint32) =
- // see e.g "C:\Program Files\Microsoft Visual Studio 2008 SDK\VisualStudioIntegration\Common\IDL\olecm.idl" for details
- //Trace.Print("CurrentDirectoryDebug", (fun () -> sprintf "curdir='%s'\n" (System.IO.Directory.GetCurrentDirectory()))) // can be useful for watching how GetCurrentDirectory changes
- match x.GetService(typeof) with
- | :? FSharpLanguageService as pl ->
- let periodic = (grfidlef &&& (uint32 _OLEIDLEF.oleidlefPeriodic)) <> 0u
- let mutable r = pl.OnIdle(periodic, mgr)
- if r = 0 && periodic && mgr.FContinueIdle() <> 0 then
- r <- TaskReporterIdleRegistration.DoIdle(mgr)
- r
- | _ -> 0
-
- override x.FPreTranslateMessage(_pMsg) = 0
-
- override x.FQueryTerminate(_fPromptUser) = 1
-
- override x.FReserved1(_dwReserved, _message, _wParam, _lParam) = 1
-
- override x.HwndGetWindow(_dwWhich, _dwReserved) = 0n
-
- override x.OnActivationChange(_pic, _fSameComponent, _pcrinfo, _fHostIsActivating, _pchostinfo, _dwReserved) = ()
-
- override x.OnAppActivate(_fActive, _dwOtherThreadID) = ()
-
- override x.OnEnterState(_uStateID, _fEnter) = ()
-
- override x.OnLoseActivation() = ()
-
- override x.Terminate() = ()
-
-
diff --git a/vsintegration/src/FSharp.LanguageService/FSharpProjectSite.fs b/vsintegration/src/FSharp.LanguageService/FSharpProjectSite.fs
new file mode 100644
index 00000000000..ff4c87ee762
--- /dev/null
+++ b/vsintegration/src/FSharp.LanguageService/FSharpProjectSite.fs
@@ -0,0 +1,83 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.LanguageService
+
+open Microsoft.VisualStudio
+open Microsoft.VisualStudio.TextManager.Interop
+open Microsoft.VisualStudio.Shell
+open Microsoft.VisualStudio.Shell.Interop
+open Microsoft.VisualStudio.FSharp.LanguageService
+open Microsoft.FSharp.Compiler.SourceCodeServices
+open Microsoft.FSharp.Compiler.AbstractIL.Diagnostics
+open Internal.Utilities.Collections
+open Internal.Utilities.Debug
+open System
+open System.IO
+open System.Diagnostics
+open System.Collections.Generic
+open Microsoft.CodeAnalysis
+open Microsoft.VisualStudio.LanguageServices.Implementation
+open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
+
+type internal FSharpProjectSite(hierarchy: IVsHierarchy, serviceProvider: System.IServiceProvider, visualStudioWorkspace: VisualStudioWorkspaceImpl, projectName: string) =
+ inherit AbstractProject(visualStudioWorkspace.ProjectTracker, null, projectName, hierarchy, "F#", serviceProvider, null, visualStudioWorkspace, null)
+
+ let mutable checkOptions : FSharpProjectOptions option = None
+
+ member internal this.CheckOptions =
+ match checkOptions with
+ | Some options -> options
+ | None -> failwith "Options haven't been computed yet."
+
+ member internal this.Initialize(hier: IVsHierarchy, site : IProjectSite) =
+ this.ProjectTracker.AddProject(this)
+
+ site.AdviseProjectSiteChanges(FSharpCommonConstants.FSharpLanguageServiceCallbackName,
+ new AdviseProjectSiteChanges(fun () -> this.OnProjectSettingsChanged(hier, site)))
+
+ site.AdviseProjectSiteClosed(FSharpCommonConstants.FSharpLanguageServiceCallbackName,
+ new AdviseProjectSiteChanges(fun () -> this.Disconnect()))
+
+ // Add files and references
+ for file in site.SourceFilesOnDisk() do this.AddDocument(hier, file)
+ for ref in this.GetReferences(site.CompilerFlags()) do this.AddReference(ref)
+
+ // Capture the F# specific options that we'll pass to the type checker.
+ checkOptions <- Some(ProjectSitesAndFiles.GetProjectOptionsForProjectSite(site, site.ProjectFileName()))
+
+ member this.GetReferences(flags : string[]) =
+ flags |> Array.choose(fun flag -> if flag.StartsWith("-r:") then Some(flag.Substring(3)) else None)
+
+ member this.AddReference(filePath : string) =
+ this.AddMetadataReferenceAndTryConvertingToProjectReferenceIfPossible(filePath, new MetadataReferenceProperties(), VSConstants.S_FALSE) |> ignore
+
+ member this.RemoveReference(filePath: string) =
+ this.RemoveMetadataReference(filePath)
+
+ member internal this.AddDocument(hier: IVsHierarchy, file : string) =
+ let itemid =
+ match hier.ParseCanonicalName(file) with
+ | (VSConstants.S_OK, id) -> id
+ | _ -> uint32 VSConstants.VSITEMID.Nil
+
+ let document = this.ProjectTracker.DocumentProvider.TryGetDocumentForFile(this, itemid, file, SourceCodeKind.Regular, fun x -> true)
+ this.AddDocument(document, true)
+
+ member internal this.OnProjectSettingsChanged(hier: IVsHierarchy, site : IProjectSite) =
+ let sourceFiles = site.SourceFilesOnDisk()
+
+ // Added files
+ for file in sourceFiles do if not(this.ContainsFile(file)) then this.AddDocument(hier, file)
+ // Removed files
+ let removedDocuments = this.GetCurrentDocuments() |> Seq.where(fun doc -> not(sourceFiles |> Seq.contains(doc.FilePath))) |> Seq.toList
+ for doc in removedDocuments do this.RemoveDocument(doc)
+
+ let references = this.GetReferences(site.CompilerFlags())
+
+ // Added references
+ for ref in references do if not(this.HasMetadataReference(ref)) then this.AddReference(ref)
+ // Removed references
+ for ref in this.GetCurrentMetadataReferences() do if not(references |> Seq.contains(ref.FilePath)) then this.RemoveReference(ref.FilePath)
+
+ // If the order of files changed, that'll be captured in the checkOptions.
+ checkOptions <- Some(ProjectSitesAndFiles.GetProjectOptionsForProjectSite(site, site.ProjectFileName()))
\ No newline at end of file
diff --git a/vsintegration/src/FSharp.LanguageService/IProjectSite.fs b/vsintegration/src/FSharp.LanguageService/IProjectSite.fs
index d7b6e498b83..e0aff674664 100644
--- a/vsintegration/src/FSharp.LanguageService/IProjectSite.fs
+++ b/vsintegration/src/FSharp.LanguageService/IProjectSite.fs
@@ -21,6 +21,9 @@ type internal IProjectSite =
/// Register for notifications when project is cleaned/rebuilt (and thus any live TypeProviders should be refreshed)
abstract AdviseProjectSiteCleaned : (*callbackOwnerKey*)string * AdviseProjectSiteChanges -> unit
+ // Register for notifications when project is closed.
+ abstract AdviseProjectSiteClosed : (*callbackOwnerKey*)string * AdviseProjectSiteChanges -> unit
+
/// A user-friendly description of the project. Used only for developer/DEBUG tooltips and such.
abstract DescriptionOfProject : unit -> string
diff --git a/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs b/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs
index cbd0f3232d0..2a6b34872f3 100644
--- a/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs
+++ b/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs
@@ -32,6 +32,7 @@ type private ProjectSiteOfScriptFile(filename:string, checkOptions : FSharpProje
override this.ErrorListTaskReporter() = None
override this.AdviseProjectSiteChanges(_,_) = ()
override this.AdviseProjectSiteCleaned(_,_) = ()
+ override this.AdviseProjectSiteClosed(_,_) = ()
override this.IsIncompleteTypeCheckEnvironment = checkOptions.IsIncompleteTypeCheckEnvironment
override this.TargetFrameworkMoniker = ""
override this.LoadTime = checkOptions.LoadTime
@@ -62,6 +63,7 @@ type private ProjectSiteOfSingleFile(sourceFile) =
override this.ErrorListTaskReporter() = None
override this.AdviseProjectSiteChanges(_,_) = ()
override this.AdviseProjectSiteCleaned(_,_) = ()
+ override this.AdviseProjectSiteClosed(_,_) = ()
override this.IsIncompleteTypeCheckEnvironment = true
override this.TargetFrameworkMoniker = ""
override this.LoadTime = new DateTime(2000,1,1) // any constant time is fine, orphan files do not interact with reloading based on update time
diff --git a/vsintegration/src/FSharp.ProjectSystem.Base/Project/ProjectSystem.Base.csproj b/vsintegration/src/FSharp.ProjectSystem.Base/Project/ProjectSystem.Base.csproj
index b6f732e1499..3e43b652632 100644
--- a/vsintegration/src/FSharp.ProjectSystem.Base/Project/ProjectSystem.Base.csproj
+++ b/vsintegration/src/FSharp.ProjectSystem.Base/Project/ProjectSystem.Base.csproj
@@ -17,7 +17,7 @@
{B700E38B-F8C0-4E49-B5EC-DB7B7AC0C4E7}$(DefineConstants);CODE_ANALYSIS;STAMP_OSS_VERSIONtrue
- v4.5
+ v4.6$(DefineConstants);FSHARP_CORE_4_5$(DefineConstants);FX_ATLEAST_45$(DefineConstants);FX_ATLEAST_40
@@ -26,7 +26,8 @@
$(DefineConstants);QUERIES_IN_FSLIB$(DefineConstants);PUT_TYPE_PROVIDERS_IN_FSCORE;$(DefineConstants);FX_ATLEAST_LINQ
-
+
+
@@ -88,7 +89,6 @@
-
@@ -101,7 +101,6 @@
-
@@ -119,7 +118,7 @@
-
+
@@ -192,6 +191,10 @@
{DED3BBD7-53F4-428A-8C9F-27968E768605}FSharp.Core
+
+ {ee85aab7-cda0-4c4e-bda0-a64ccc413e3f}
+ FSharp.LanguageService
+
\ No newline at end of file
diff --git a/vsintegration/src/FSharp.ProjectSystem.FSharp/Project.fs b/vsintegration/src/FSharp.ProjectSystem.FSharp/Project.fs
index 378d82dc50f..b403d93d457 100644
--- a/vsintegration/src/FSharp.ProjectSystem.FSharp/Project.fs
+++ b/vsintegration/src/FSharp.ProjectSystem.FSharp/Project.fs
@@ -105,6 +105,7 @@ namespace Microsoft.VisualStudio.FSharp.ProjectSystem
member ips.ProjectFileName() = inner.ProjectFileName()
member ips.AdviseProjectSiteChanges(callbackOwnerKey,callback) = inner.AdviseProjectSiteChanges(callbackOwnerKey, callback)
member ips.AdviseProjectSiteCleaned(callbackOwnerKey,callback) = inner.AdviseProjectSiteCleaned(callbackOwnerKey, callback)
+ member ips.AdviseProjectSiteClosed(callbackOwnerKey,callback) = inner.AdviseProjectSiteClosed(callbackOwnerKey, callback)
member ips.ErrorListTaskProvider() = inner.ErrorListTaskProvider()
member ips.ErrorListTaskReporter() = inner.ErrorListTaskReporter()
member ips.TargetFrameworkMoniker = inner.TargetFrameworkMoniker
@@ -472,6 +473,7 @@ See also ...\SetupAuthoring\FSharp\Registry\FSProjSys_Registration.wxs, e.g.
let sourcesAndFlagsNotifier = new Notifier()
let cleanNotifier = new Notifier()
+ let closeNotifier = new Notifier()
[]
static val mutable private imageOffset : int
@@ -648,6 +650,7 @@ See also ...\SetupAuthoring\FSharp\Registry\FSProjSys_Registration.wxs, e.g.
| _ -> ()
vsProject <- null
accessor <- null
+ closeNotifier.Notify()
base.Close()
override x.Load(filename:string, location:string, name:string, flags:uint32, iidProject:byref, canceled:byref ) =
@@ -1611,6 +1614,8 @@ See also ...\SetupAuthoring\FSharp\Registry\FSProjSys_Registration.wxs, e.g.
sourcesAndFlagsNotifier.Advise(callbackOwnerKey,callback)
member this.AdviseProjectSiteCleaned(callbackOwnerKey,callback) =
cleanNotifier.Advise(callbackOwnerKey,callback)
+ member this.AdviseProjectSiteClosed(callbackOwnerKey,callback) =
+ closeNotifier.Advise(callbackOwnerKey,callback)
member this.IsIncompleteTypeCheckEnvironment = false
member this.TargetFrameworkMoniker = x.GetTargetFrameworkMoniker()
member this.LoadTime = creationTime
@@ -1640,6 +1645,7 @@ See also ...\SetupAuthoring\FSharp\Registry\FSProjSys_Registration.wxs, e.g.
member ips.ErrorListTaskReporter() = taskReporter
member this.AdviseProjectSiteChanges(_,_) = ()
member this.AdviseProjectSiteCleaned(_,_) = ()
+ member this.AdviseProjectSiteClosed(_,_) = ()
member this.IsIncompleteTypeCheckEnvironment = false
member this.TargetFrameworkMoniker = targetFrameworkMoniker
member this.LoadTime = creationTime
diff --git a/vsintegration/src/FSharp.ProjectSystem.FSharp/ProjectSystem.fsproj b/vsintegration/src/FSharp.ProjectSystem.FSharp/ProjectSystem.fsproj
index 45d7cbe1691..e882258a34e 100644
--- a/vsintegration/src/FSharp.ProjectSystem.FSharp/ProjectSystem.fsproj
+++ b/vsintegration/src/FSharp.ProjectSystem.FSharp/ProjectSystem.fsproj
@@ -7,6 +7,7 @@
true$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\VSSDK14.0
+ v4.6Debug
diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/DesignFramework/DesignerMessageBox.vb b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/DesignFramework/DesignerMessageBox.vb
index a0e67740fbc..9465b046c15 100644
--- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/DesignFramework/DesignerMessageBox.vb
+++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/DesignFramework/DesignerMessageBox.vb
@@ -76,7 +76,7 @@ Namespace Microsoft.VisualStudio.Editors.DesignerFramework
End If
'Pull out the original exception from target invocation exceptions (happen during serialization, etc.)
- If TypeOf ex Is Reflection.TargetInvocationException Then
+ If TypeOf ex Is System.Reflection.TargetInvocationException Then
ex = ex.InnerException
End If
diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/FSharp.PropertiesPages.vbproj b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/FSharp.PropertiesPages.vbproj
index c691d52d833..e5f3d3f5254 100644
--- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/FSharp.PropertiesPages.vbproj
+++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/FSharp.PropertiesPages.vbproj
@@ -28,7 +28,7 @@
40026;42105;42107;42353true
- v4.5
+ v4.6$(DefineConstants),FSHARP_CORE_4_5=True$(DefineConstants),FX_ATLEAST_45=True$(DefineConstants),FX_ATLEAST_40=True
diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/BuildPropPage.vb b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/BuildPropPage.vb
index 51efaa35c58..160fefc8a6e 100644
--- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/BuildPropPage.vb
+++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/BuildPropPage.vb
@@ -596,7 +596,7 @@ Namespace Microsoft.VisualStudio.Editors.PropertyPages
Catch ex As InvalidCastException
'// When all else fails assume dll (so they can edit it)
OutputType = VSLangProj.prjOutputType.prjOutputTypeLibrary
- Catch ex As Reflection.TargetInvocationException
+ Catch ex As System.Reflection.TargetInvocationException
' Property must be missing for this project flavor
OutputType = VSLangProj.prjOutputType.prjOutputTypeLibrary
End Try
diff --git a/vsintegration/tests/Salsa/FSharpLanguageServiceTestable.fs b/vsintegration/tests/Salsa/FSharpLanguageServiceTestable.fs
new file mode 100644
index 00000000000..5d6fe745bac
--- /dev/null
+++ b/vsintegration/tests/Salsa/FSharpLanguageServiceTestable.fs
@@ -0,0 +1,223 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Salsa
+
+open System
+open System.IO
+open System.Collections.Generic
+open System.Configuration
+open System.Globalization
+open System.Runtime.InteropServices
+open Microsoft.VisualStudio
+open Microsoft.VisualStudio.Shell
+open Microsoft.VisualStudio.Shell.Interop
+open Microsoft.VisualStudio.TextManager.Interop
+open Microsoft.VisualStudio.Text
+open Microsoft.VisualStudio.OLE.Interop
+open Microsoft.FSharp.Compiler
+open Microsoft.FSharp.Compiler.SourceCodeServices
+open Microsoft.VisualStudio.FSharp.LanguageService
+
+type internal FSharpLanguageServiceTestable() as this =
+ static let colorizerGuid = new Guid("{A2976312-7D71-4BB4-A5F8-66A08EBF46C8}") // Guid for colorized user data on IVsTextBuffer
+ let mutable checkerContainerOpt : FSharpChecker option = None
+ let mutable artifacts : ProjectSitesAndFiles option = None
+ let mutable serviceProvider : System.IServiceProvider option = None
+ let mutable preferences : LanguagePreferences option = None
+ let mutable documentationBuilder : IDocumentationBuilder option = None
+ let mutable sourceFactory : (IVsTextLines -> IFSharpSource) option = None
+ let mutable dirtyForTypeCheckFiles : Set = Set.empty
+ let mutable isInitialized = false
+ let mutable unhooked = false
+ let getColorizer (view:IVsTextView) =
+ let buffer = Com.ThrowOnFailure1(view.GetBuffer())
+ this.GetColorizer(buffer)
+
+ let bgRequests = new FSharpLanguageServiceBackgroundRequests(getColorizer,(fun () -> this.FSharpChecker),(fun () -> this.ProjectSitesAndFiles),(fun () -> this.ServiceProvider),(fun () -> this.DocumentationBuilder))
+
+ member this.FSharpChecker =
+ if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
+ if not this.IsInitialized then raise Error.UseOfUninitializedLanguageServiceState
+ checkerContainerOpt.Value
+
+ member this.ServiceProvider =
+ if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
+ if not this.IsInitialized then raise Error.UseOfUninitializedLanguageServiceState
+ serviceProvider.Value
+
+ member this.ProjectSitesAndFiles =
+ if not this.IsInitialized then raise Error.UseOfUninitializedLanguageServiceState
+ artifacts.Value
+
+ member this.Preferences =
+ if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
+ if not this.IsInitialized then raise Error.UseOfUninitializedLanguageServiceState
+ preferences.Value
+
+ member this.SourceFactory =
+ if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
+ if not this.IsInitialized then raise Error.UseOfUninitializedLanguageServiceState
+ sourceFactory.Value
+
+ member this.IsInitialized = isInitialized
+ member this.Unhooked = unhooked
+ member this.DocumentationBuilder = documentationBuilder.Value
+
+ /// Handle late intialization pieces
+ member this.Initialize (sp, dp, prefs, sourceFact) =
+ if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
+ artifacts <- Some (ProjectSitesAndFiles())
+ let checker = FSharpChecker.Create()
+ checker.BeforeBackgroundFileCheck.Add (fun filename -> UIThread.Run(fun () -> this.NotifyFileTypeCheckStateIsDirty(filename)))
+ checkerContainerOpt <- Some (checker)
+ serviceProvider <- Some sp
+ isInitialized <- true
+ unhooked <- false
+ documentationBuilder <- Some dp
+ preferences <- Some prefs
+ sourceFactory <- Some sourceFact
+
+
+ member this.NotifyFileTypeCheckStateIsDirty(filename) =
+ dirtyForTypeCheckFiles <- dirtyForTypeCheckFiles.Add filename
+
+ /// Clear all language service caches and finalize all transient references to compiler objects
+ member this.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() =
+ if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
+ if this.IsInitialized then
+ this.FSharpChecker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients()
+
+ /// Unhook the object. These are the held resources that need to be disposed.
+ member this.Unhook() =
+ if this.Unhooked then raise Error.UseOfUnhookedLanguageServiceState
+ if this.IsInitialized then
+ // Dispose the preferences.
+ if this.Preferences <> null then this.Preferences.Dispose()
+ // Stop the background compile.
+ // here we refer to checkerContainerOpt directly to avoid triggering its creation
+ match checkerContainerOpt with
+ | Some container ->
+ let checker = container
+ checker.StopBackgroundCompile()
+ checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients()
+ | None -> ()
+
+ checkerContainerOpt <- None
+ artifacts <- None
+ preferences <- None
+ documentationBuilder <- None
+ unhooked <- true
+ sourceFactory <- None
+ serviceProvider <- None
+
+ /// Respond to project settings changes
+ member this.OnProjectSettingsChanged(site:IProjectSite) =
+ // The project may have changed its references. These would be represented as 'dependency files' of each source file. Each source file will eventually start listening
+ // for changes to those dependencies, at which point we'll get OnDependencyFileCreateOrDelete notifications. Until then, though, we just 'make a note' that this project is out of date.
+ bgRequests.AddOutOfDateProjectFileName(site.ProjectFileName())
+ for filename in site.SourceFilesOnDisk() do
+ let rdt = this.ServiceProvider.RunningDocumentTable
+ match this.ProjectSitesAndFiles.TryGetSourceOfFile(rdt,filename) with
+ | Some source ->
+ source.RecolorizeWholeFile()
+ source.RecordChangeToView()
+ | None -> ()
+
+ /// Respond to project being cleaned/rebuilt (any live type providers in the project should be refreshed)
+ member this.OnProjectCleaned(projectSite:IProjectSite) =
+ let checkOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(projectSite, "")
+ this.FSharpChecker.NotifyProjectCleaned(checkOptions)
+
+ member this.OnActiveViewChanged(textView) =
+ bgRequests.OnActiveViewChanged(textView)
+
+ member this.BackgroundRequests = bgRequests
+
+ /// Unittestable complement to LanguageServce.CreateSource
+ member this.CreateSource(buffer:IVsTextLines) : IFSharpSource =
+
+ // Each time a source is created, also verify that the IProjectSite has been initialized to listen to changes to the project.
+ // We can't listen to OnProjectLoaded because the language service is not guaranteed to be loaded when this is called.
+ let filename = VsTextLines.GetFilename buffer
+ let rdt = this.ServiceProvider.RunningDocumentTable
+ let result = VsRunningDocumentTable.FindDocumentWithoutLocking(rdt,filename)
+ match result with
+ | Some(hier,_) ->
+ match hier with
+ | :? IProvideProjectSite as siteProvider ->
+ let site = siteProvider.GetProjectSite()
+ site.AdviseProjectSiteChanges(FSharpCommonConstants.FSharpLanguageServiceCallbackName,
+ new AdviseProjectSiteChanges(fun () -> this.OnProjectSettingsChanged(site)))
+ site.AdviseProjectSiteCleaned(FSharpCommonConstants.FSharpLanguageServiceCallbackName,
+ new AdviseProjectSiteChanges(fun () -> this.OnProjectCleaned(site)))
+ | _ ->
+ // This can happen when the file is in a solution folder or in, say, a C# project.
+ ()
+ | _ ->
+ // This can happen when renaming a file from a different language service into .fs or fsx.
+ // This naturally won't have an associated project.
+ ()
+
+ // Create the source and register file change callbacks there.
+ let source = this.SourceFactory(buffer)
+ this.ProjectSitesAndFiles.SetSource(buffer, source)
+ source
+
+ // For each change in dependency files, notify the language service of the change and propagate the update
+ interface IDependencyFileChangeNotify with
+ member this.DependencyFileCreated projectSite =
+ // Invalidate the configuration if we notice any add for any DependencyFiles
+ let checkOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(projectSite, "")
+ this.FSharpChecker.InvalidateConfiguration(checkOptions)
+
+ member this.DependencyFileChanged (filename) =
+ this.NotifyFileTypeCheckStateIsDirty filename
+
+
+ /// Do OnIdle processing for the whole language service. dirtyForTypeCheckFiles can be set by events
+ /// raised on the background compilation thread.
+ member this.OnIdle() =
+ for file in dirtyForTypeCheckFiles do
+ let rdt = this.ServiceProvider.RunningDocumentTable
+ match this.ProjectSitesAndFiles.TryGetSourceOfFile(rdt, file) with
+ | Some source -> source.RecordChangeToView()
+ | None -> ()
+ dirtyForTypeCheckFiles <- Set.empty
+
+
+ /// Remove a colorizer.
+ member this.CloseColorizer(colorizer:FSharpColorizer) =
+ let buffer = colorizer.Buffer
+ let mutable guid = colorizerGuid
+ (buffer :?> IVsUserData).SetData(&guid, null) |> ErrorHandler.ThrowOnFailure |> ignore
+
+ /// Get a colorizer for a particular buffer.
+ member this.GetColorizer(buffer:IVsTextLines) : FSharpColorizer =
+ let mutable guid = colorizerGuid
+ let mutable colorizerObj = null
+
+ (buffer :?> IVsUserData).GetData(&guid, &colorizerObj) |> ignore
+ match colorizerObj with
+ | null ->
+ let scanner =
+ new FSharpScanner(fun source ->
+ // Note: in theory, the next few lines do not need to be recomputed every line. Instead we could just cache the tokenizer
+ // and only update it when e.g. the project system notifies us there is an important change (e.g. a file rename, etc).
+ // In practice we have been there, and always screwed up some non-unit-tested/testable corner-cases.
+ // So this is not ideal from a perf perspective, but it is easy to reason about the correctness.
+ let filename = VsTextLines.GetFilename buffer
+ let rdt = this.ServiceProvider.RunningDocumentTable
+ let defines = this.ProjectSitesAndFiles.GetDefinesForFile(rdt, filename)
+ let sourceTokenizer = FSharpSourceTokenizer(defines,filename)
+ sourceTokenizer.CreateLineTokenizer(source))
+
+ let colorizer = new FSharpColorizer(this.CloseColorizer, buffer, scanner)
+ (buffer :?> IVsUserData).SetData(&guid, colorizer) |> ErrorHandler.ThrowOnFailure |> ignore
+ colorizer
+ | _ -> colorizerObj :?> FSharpColorizer
+
+ /// Block until the background compile finishes.
+ //
+ // This is for unit testing only
+ member this.WaitForBackgroundCompile() =
+ this.FSharpChecker.WaitForBackgroundCompile()
\ No newline at end of file
diff --git a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
index b77bc4791fd..32e441c2b39 100644
--- a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
+++ b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
@@ -6,6 +6,7 @@
FSharptrueVisualFSharp.Salsa
+ v4.6
@@ -26,6 +27,7 @@
UnitTests.TestLib.Utils.fs
+
@@ -40,6 +42,7 @@
+
diff --git a/vsintegration/tests/Salsa/salsa.fs b/vsintegration/tests/Salsa/salsa.fs
index 1a50ad15b4d..32923a5e777 100644
--- a/vsintegration/tests/Salsa/salsa.fs
+++ b/vsintegration/tests/Salsa/salsa.fs
@@ -312,6 +312,7 @@ module internal Salsa =
member this.ErrorListTaskReporter() = None
member this.AdviseProjectSiteChanges(callbackOwnerKey,callback) = changeHandlers.[callbackOwnerKey] <- callback
member this.AdviseProjectSiteCleaned(callbackOwnerKey,callback) = () // no unit testing support here
+ member this.AdviseProjectSiteClosed(callbackOwnerKey,callback) = () // no unit testing support here
member this.IsIncompleteTypeCheckEnvironment = false
member this.TargetFrameworkMoniker = ""
member this.LoadTime = System.DateTime(2000,1,1)
diff --git a/vsintegration/tests/unittests/VisualFSharp.Unittests.fsproj b/vsintegration/tests/unittests/VisualFSharp.Unittests.fsproj
index 1b7609ba006..38fcc5afe42 100644
--- a/vsintegration/tests/unittests/VisualFSharp.Unittests.fsproj
+++ b/vsintegration/tests/unittests/VisualFSharp.Unittests.fsproj
@@ -6,6 +6,7 @@
FSharptrueVisualFSharp.Unittests
+ v4.6