From 2b5d15862e2bc896465bb35855f79fda68cf090a Mon Sep 17 00:00:00 2001 From: Omar Tawfik Date: Thu, 13 Oct 2016 16:56:52 -0700 Subject: [PATCH 1/3] Add fsx files to workspaces --- .../src/FSharp.Editor/LanguageService.fs | 83 +++++++++++++------ 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService.fs index baefd3079e0..3d027d0ddab 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService.fs @@ -8,6 +8,7 @@ open System.Runtime.InteropServices open System.Linq open System.IO +open Microsoft.FSharp.Compiler.CompileOps open Microsoft.FSharp.Compiler.SourceCodeServices open Microsoft.CodeAnalysis @@ -74,35 +75,63 @@ type internal FSharpLanguageService(package : FSharpPackage) = let result = VsRunningDocumentTable.FindDocumentWithoutLocking(package.RunningDocumentTable,filename) match result with | Some (hier, _) -> - match hier with - | :? IProvideProjectSite as siteProvider -> - let site = siteProvider.GetProjectSite() - let projectGuid = Guid(site.ProjectGuid) - let projectFileName = site.ProjectFileName() - let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectFileName) - - let options = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(site, site.ProjectFileName()) - if not (optionsCache.ContainsKey(projectId)) then - optionsCache.Add(projectId, options) - - if obj.ReferenceEquals(workspace.ProjectTracker.GetProject(projectId), null) then - let projectContextFactory = this.Package.ComponentModel.GetService(); - let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider) - let outputFlag = site.CompilerFlags() |> Seq.pick(fun flag -> - if flag.StartsWith("-o:") then Some(flag.Substring(3)) - else if flag.StartsWith("--out:") then Some(flag.Substring(6)) - else None) - let outputPath = if Path.IsPathRooted(outputFlag) then outputFlag else Path.Combine(Path.GetDirectoryName(projectFileName), outputFlag) - - let projectContext = projectContextFactory.CreateProjectContext(FSharpCommonConstants.FSharpLanguageName, projectFileName, projectFileName, projectGuid, hier, outputPath, errorReporter) - let project = projectContext :?> AbstractProject - - this.SyncProject(project, projectContext, site) - site.AdviseProjectSiteChanges(FSharpCommonConstants.FSharpLanguageServiceCallbackName, AdviseProjectSiteChanges(fun () -> this.SyncProject(project, projectContext, site))) - site.AdviseProjectSiteClosed(FSharpCommonConstants.FSharpLanguageServiceCallbackName, AdviseProjectSiteChanges(fun () -> project.Disconnect())) - | _ -> () + if IsScript(filename) then + this.SetupStandAloneFile(filename, workspace, hier) + else + match hier with + | :? IProvideProjectSite as siteProvider -> this.SetupProjectFile(siteProvider, workspace) + | _ -> () | _ -> () + member this.SetupProjectFile(siteProvider: IProvideProjectSite, workspace: VisualStudioWorkspaceImpl) = + let site = siteProvider.GetProjectSite() + let projectGuid = Guid(site.ProjectGuid) + let projectFileName = site.ProjectFileName() + let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectFileName) + + let options = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(site, site.ProjectFileName()) + if not (optionsCache.ContainsKey(projectId)) then + optionsCache.Add(projectId, options) + + match workspace.ProjectTracker.GetProject(projectId) with + | null -> + let projectContextFactory = this.Package.ComponentModel.GetService(); + let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider) + let outputFlag = site.CompilerFlags() |> Seq.pick(fun flag -> + if flag.StartsWith("-o:") then Some(flag.Substring(3)) + else if flag.StartsWith("--out:") then Some(flag.Substring(6)) + else None) + let outputPath = if Path.IsPathRooted(outputFlag) then outputFlag else Path.Combine(Path.GetDirectoryName(projectFileName), outputFlag) + + let projectContext = projectContextFactory.CreateProjectContext(FSharpCommonConstants.FSharpLanguageName, projectFileName, projectFileName, projectGuid, siteProvider, outputPath, errorReporter) + let project = projectContext :?> AbstractProject + + this.SyncProject(project, projectContext, site) + site.AdviseProjectSiteChanges(FSharpCommonConstants.FSharpLanguageServiceCallbackName, AdviseProjectSiteChanges(fun () -> this.SyncProject(project, projectContext, site))) + site.AdviseProjectSiteClosed(FSharpCommonConstants.FSharpLanguageServiceCallbackName, AdviseProjectSiteChanges(fun () -> project.Disconnect())) + | _ -> () + + member this.SetupStandAloneFile(fileName: string, workspace: VisualStudioWorkspaceImpl, hier: IVsHierarchy) = + let sourceText = File.ReadAllText(fileName) + let options = FSharpChecker.Instance.GetProjectOptionsFromScript(fileName, sourceText, DateTime.Now, [| |]) |> Async.RunSynchronously + let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(options.ProjectFileName, options.ProjectFileName) + + if not(optionsCache.ContainsKey(projectId)) then + optionsCache.Add(projectId, options) + + if obj.ReferenceEquals(workspace.ProjectTracker.GetProject(projectId), null) then + let projectContextFactory = this.Package.ComponentModel.GetService(); + let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider) + + let projectContext = projectContextFactory.CreateProjectContext(FSharpCommonConstants.FSharpLanguageName, options.ProjectFileName, options.ProjectFileName, projectId.Id, hier, null, errorReporter) + projectContext.AddSourceFile(fileName) + + let project = projectContext :?> AbstractProject + let document = project.GetCurrentDocumentFromPath(fileName) + + document.Closing.Add(fun _ -> project.Disconnect()) + + and [] [] [] From cb380c5f06bb6bff9b531b7fa4454616ad70e854 Mon Sep 17 00:00:00 2001 From: Omar Tawfik Date: Fri, 14 Oct 2016 14:23:38 -0700 Subject: [PATCH 2/3] Stop passing project output paths to CPS --- vsintegration/src/FSharp.Editor/LanguageService.fs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService.fs index 3d027d0ddab..5f22a525943 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService.fs @@ -97,13 +97,8 @@ type internal FSharpLanguageService(package : FSharpPackage) = | null -> let projectContextFactory = this.Package.ComponentModel.GetService(); let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider) - let outputFlag = site.CompilerFlags() |> Seq.pick(fun flag -> - if flag.StartsWith("-o:") then Some(flag.Substring(3)) - else if flag.StartsWith("--out:") then Some(flag.Substring(6)) - else None) - let outputPath = if Path.IsPathRooted(outputFlag) then outputFlag else Path.Combine(Path.GetDirectoryName(projectFileName), outputFlag) - let projectContext = projectContextFactory.CreateProjectContext(FSharpCommonConstants.FSharpLanguageName, projectFileName, projectFileName, projectGuid, siteProvider, outputPath, errorReporter) + let projectContext = projectContextFactory.CreateProjectContext(FSharpCommonConstants.FSharpLanguageName, projectFileName, projectFileName, projectGuid, siteProvider, null, errorReporter) let project = projectContext :?> AbstractProject this.SyncProject(project, projectContext, site) From 272edd5c912864b3bb871571406f8ce1874ae584 Mon Sep 17 00:00:00 2001 From: Omar Tawfik Date: Fri, 14 Oct 2016 15:45:35 -0700 Subject: [PATCH 3/3] Read script file contents from memory (on workspace initialization) --- .../src/FSharp.Editor/LanguageService.fs | 38 ++++++++++--------- .../src/FSharp.LanguageService/Vs.fs | 6 +++ 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService.fs index 5f22a525943..1aeda6a46a0 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService.fs @@ -14,6 +14,8 @@ open Microsoft.FSharp.Compiler.SourceCodeServices open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Editor.Options open Microsoft.VisualStudio +open Microsoft.VisualStudio.Editor +open Microsoft.VisualStudio.TextManager.Interop open Microsoft.VisualStudio.LanguageServices open Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem @@ -63,24 +65,27 @@ type internal FSharpLanguageService(package : FSharpPackage) = override this.CreateContext(_,_,_,_,_) = raise(System.NotImplementedException()) - override this.SetupNewTextView(view) = - base.SetupNewTextView(view) - let workspace = this.Package.ComponentModel.GetService(); + override this.SetupNewTextView(textView) = + base.SetupNewTextView(textView) + let workspace = this.Package.ComponentModel.GetService() // FSROSLYNTODO: Hide navigation bars for now. Enable after adding tests workspace.Options <- workspace.Options.WithChangedOption(NavigationBarOptions.ShowNavigationBar, FSharpCommonConstants.FSharpLanguageName, false) - let (_, buffer) = view.GetBuffer() - let filename = VsTextLines.GetFilename buffer - let result = VsRunningDocumentTable.FindDocumentWithoutLocking(package.RunningDocumentTable,filename) - match result with - | Some (hier, _) -> - if IsScript(filename) then - this.SetupStandAloneFile(filename, workspace, hier) - else - match hier with - | :? IProvideProjectSite as siteProvider -> this.SetupProjectFile(siteProvider, workspace) - | _ -> () + match textView.GetBuffer() with + | (VSConstants.S_OK, textLines) -> + let filename = VsTextLines.GetFilename textLines + match VsRunningDocumentTable.FindDocumentWithoutLocking(package.RunningDocumentTable,filename) with + | Some (hier, _) -> + if IsScript(filename) then + let editorAdapterFactoryService = this.Package.ComponentModel.GetService() + let fileContents = VsTextLines.GetFileContents(textLines, editorAdapterFactoryService) + this.SetupStandAloneFile(filename, fileContents, workspace, hier) + else + match hier with + | :? IProvideProjectSite as siteProvider -> this.SetupProjectFile(siteProvider, workspace) + | _ -> () + | _ -> () | _ -> () member this.SetupProjectFile(siteProvider: IProvideProjectSite, workspace: VisualStudioWorkspaceImpl) = @@ -106,9 +111,8 @@ type internal FSharpLanguageService(package : FSharpPackage) = site.AdviseProjectSiteClosed(FSharpCommonConstants.FSharpLanguageServiceCallbackName, AdviseProjectSiteChanges(fun () -> project.Disconnect())) | _ -> () - member this.SetupStandAloneFile(fileName: string, workspace: VisualStudioWorkspaceImpl, hier: IVsHierarchy) = - let sourceText = File.ReadAllText(fileName) - let options = FSharpChecker.Instance.GetProjectOptionsFromScript(fileName, sourceText, DateTime.Now, [| |]) |> Async.RunSynchronously + member this.SetupStandAloneFile(fileName: string, fileContents: string, workspace: VisualStudioWorkspaceImpl, hier: IVsHierarchy) = + let options = FSharpChecker.Instance.GetProjectOptionsFromScript(fileName, fileContents, DateTime.Now, [| |]) |> Async.RunSynchronously let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(options.ProjectFileName, options.ProjectFileName) if not(optionsCache.ContainsKey(projectId)) then diff --git a/vsintegration/src/FSharp.LanguageService/Vs.fs b/vsintegration/src/FSharp.LanguageService/Vs.fs index a79e42f008c..6c67be30c61 100644 --- a/vsintegration/src/FSharp.LanguageService/Vs.fs +++ b/vsintegration/src/FSharp.LanguageService/Vs.fs @@ -8,6 +8,7 @@ open System.Collections open System.Collections.Generic open System.Reflection open Microsoft.VisualStudio +open Microsoft.VisualStudio.Editor open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.Text @@ -177,6 +178,11 @@ module internal VsTextLines = let GetFilename(buffer : IVsTextLines) = let ud = (box buffer) :?> IVsUserData VsUserData.GetBufferMonker(ud) + + /// Get the string contents of a given buffer (the current snapshot). + let GetFileContents(buffer: IVsTextBuffer, editorAdaptersFactoryService: IVsEditorAdaptersFactoryService) = + let dataBuffer = editorAdaptersFactoryService.GetDataBuffer(buffer) + dataBuffer.CurrentSnapshot.GetText() module internal VsRunningDocumentTable =