From 30777cc1710c003c0ba8a2fc2235896e99f7c902 Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 29 Nov 2019 16:57:51 +0000 Subject: [PATCH 001/101] Compiles --- .../BraceCompletionSessionProvider.fs | 4 +- .../ClassificationDefinitions.fs | 178 ++++++++-------- ...eywordToDisposableConstructorInvocation.fs | 2 +- .../FSharp.Editor/CodeFix/FixIndexerAccess.fs | 3 +- .../CodeFix/ProposeUppercaseLabel.fs | 2 +- .../CodeFix/RenameParamToMatchSignature.fs | 2 +- .../CodeFix/ReplaceWithSuggestion.fs | 5 +- .../src/FSharp.Editor/CodeFix/SimplifyName.fs | 4 +- .../CodeLens/CodeLensProvider.fs | 2 +- .../CodeLens/FSharpCodeLensService.fs | 4 +- .../Commands/FsiCommandService.fs | 4 +- .../Commands/XmlDocCommandService.fs | 2 +- .../src/FSharp.Editor/Common/RoslynHelpers.fs | 2 +- .../DocComments/XMLDocumentation.fs | 2 +- .../FSharp.Editor/FSharp.Editor.Designer.fs | 157 ++++++++++++++ .../src/FSharp.Editor/FSharp.Editor.fsproj | 200 +++++++++--------- .../LanguageService/FSharpCheckerProvider.fs | 2 +- .../LanguageService/LanguageService.fs | 94 ++++---- .../Navigation/NavigableSymbolsService.fs | 16 +- .../Navigation/NavigateToSearchService.fs | 50 ++--- .../FSharp.Editor/Options/EditorOptionsMac.fs | 140 ++++++++++++ .../Options/SettingsPersistence.fs | 70 +++--- .../QuickInfo/QuickInfoProvider.fs | 8 +- .../WpfNagivableTextRunViewElementFactory.fs | 6 +- 24 files changed, 625 insertions(+), 334 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/FSharp.Editor.Designer.fs create mode 100644 vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs diff --git a/vsintegration/src/FSharp.Editor/AutomaticCompletion/BraceCompletionSessionProvider.fs b/vsintegration/src/FSharp.Editor/AutomaticCompletion/BraceCompletionSessionProvider.fs index dd3be821094..3ad729fc4a3 100644 --- a/vsintegration/src/FSharp.Editor/AutomaticCompletion/BraceCompletionSessionProvider.fs +++ b/vsintegration/src/FSharp.Editor/AutomaticCompletion/BraceCompletionSessionProvider.fs @@ -12,7 +12,7 @@ open Microsoft.VisualStudio.Text.BraceCompletion open Microsoft.VisualStudio.Text.Operations open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor -open Microsoft.VisualStudio.Utilities +//open Microsoft.VisualStudio.Utilities open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.Host @@ -504,7 +504,7 @@ type EditorBraceCompletionSessionFactory() = null [)>] -[] +//[] [] [] [] diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs index 749c3ceed7a..9e995c44a9a 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs @@ -14,7 +14,7 @@ open Microsoft.VisualStudio.Shell.Interop open Microsoft.Internal.VisualStudio.Shell.Interop open Microsoft.VisualStudio.Language.StandardClassification open Microsoft.VisualStudio.Text.Classification -open Microsoft.VisualStudio.Utilities +//open Microsoft.VisualStudio.Utilities open Microsoft.CodeAnalysis.Classification open FSharp.Compiler.SourceCodeServices @@ -60,7 +60,7 @@ module internal ClassificationDefinitions = [] ( classificationformatMapService: IClassificationFormatMapService, - classificationTypeRegistry: IClassificationTypeRegistryService, + //classificationTypeRegistry: IClassificationTypeRegistryService, [)>] serviceProvider: IServiceProvider ) = @@ -73,12 +73,12 @@ module internal ClassificationDefinitions = let themeService = serviceProvider.GetService(typeof) :?> IVsColorThemeService themeService.CurrentTheme.ThemeId - let colorData = // name, (light, dark) - [ FSharpClassificationTypes.Function, (Colors.Black, Color.FromRgb(220uy, 220uy, 220uy)) - FSharpClassificationTypes.MutableVar, (Color.FromRgb(160uy, 128uy, 0uy), Color.FromRgb(255uy, 210uy, 28uy)) - FSharpClassificationTypes.Printf, (Color.FromRgb(43uy, 145uy, 175uy), Color.FromRgb(78uy, 220uy, 176uy)) - FSharpClassificationTypes.Property, (Colors.Black, Color.FromRgb(220uy, 220uy, 220uy)) - FSharpClassificationTypes.Disposable, (Color.FromRgb(43uy, 145uy, 175uy), Color.FromRgb(78uy, 220uy, 176uy)) ] + //let colorData = // name, (light, dark) + //[ FSharpClassificationTypes.Function, (Colors.Black, Color.FromRgb(220uy, 220uy, 220uy)) + //FSharpClassificationTypes.MutableVar, (Color.FromRgb(160uy, 128uy, 0uy), Color.FromRgb(255uy, 210uy, 28uy)) + //FSharpClassificationTypes.Printf, (Color.FromRgb(43uy, 145uy, 175uy), Color.FromRgb(78uy, 220uy, 176uy)) + //FSharpClassificationTypes.Property, (Colors.Black, Color.FromRgb(220uy, 220uy, 220uy)) + //FSharpClassificationTypes.Disposable, (Color.FromRgb(43uy, 145uy, 175uy), Color.FromRgb(78uy, 220uy, 176uy)) ] let setColors _ = @@ -90,16 +90,16 @@ module internal ClassificationDefinitions = let formatMap = classificationformatMapService.GetClassificationFormatMap(category = "text") try formatMap.BeginBatchUpdate() - for ctype, (light, dark) in colorData do - // we don't touch the changes made by the user - if fontAndColorStorage.GetItem(ctype, Array.zeroCreate 1) <> VSConstants.S_OK then - let ict = classificationTypeRegistry.GetClassificationType(ctype) - let oldProps = formatMap.GetTextProperties(ict) - let newProps = match getCurrentThemeId() with - | LightTheme -> oldProps.SetForeground light - | DarkTheme -> oldProps.SetForeground dark - | UnknownTheme -> oldProps - formatMap.SetTextProperties(ict, newProps) + //for ctype, (light, dark) in colorData do + //// we don't touch the changes made by the user + //if fontAndColorStorage.GetItem(ctype, Array.zeroCreate 1) <> VSConstants.S_OK then + //let ict = classificationTypeRegistry.GetClassificationType(ctype) + //let oldProps = formatMap.GetTextProperties(ict) + //let newProps = oldProps //match getCurrentThemeId() with + // //| LightTheme -> oldProps.SetForeground light + // //| DarkTheme -> oldProps.SetForeground dark + // //| UnknownTheme -> oldProps + //formatMap.SetTextProperties(ict, newProps) fontAndColorStorage.CloseCategory() |> ignore finally formatMap.EndBatchUpdate() @@ -107,80 +107,80 @@ module internal ClassificationDefinitions = do VSColorTheme.add_ThemeChanged handler interface IDisposable with member __.Dispose() = VSColorTheme.remove_ThemeChanged handler - member __.GetColor(ctype) = - let light, dark = colorData |> Map.ofList |> Map.find ctype + member __.GetColor(_ctype) = + //let light, dark = colorData |> Map.ofList |> Map.find ctype match getCurrentThemeId() with - | LightTheme -> Nullable light - | DarkTheme -> Nullable dark + | LightTheme -> Nullable() + | DarkTheme -> Nullable() | UnknownTheme -> Nullable() interface ISetThemeColors with member this.SetColors() = setColors() - [] - let FSharpFunctionClassificationType : ClassificationTypeDefinition = null - - [] - let FSharpMutableVarClassificationType : ClassificationTypeDefinition = null - - [] - let FSharpPrintfClassificationType : ClassificationTypeDefinition = null - - [] - let FSharpPropertyClassificationType : ClassificationTypeDefinition = null - - [] - let FSharpDisposableClassificationType : ClassificationTypeDefinition = null - - [)>] - [] - [] - [] - [] - type internal FSharpFunctionTypeFormat() as self = - inherit ClassificationFormatDefinition() - - do self.DisplayName <- SR.FSharpFunctionsOrMethodsClassificationType() - - [)>] - [] - [] - [] - [] - type internal FSharpMutableVarTypeFormat [](theme: ThemeColors) as self = - inherit ClassificationFormatDefinition() - - do self.DisplayName <- SR.FSharpMutableVarsClassificationType() - self.ForegroundColor <- theme.GetColor FSharpClassificationTypes.MutableVar - - [)>] - [] - [] - [] - [] - type internal FSharpPrintfTypeFormat [](theme: ThemeColors) as self = - inherit ClassificationFormatDefinition() - - do self.DisplayName <- SR.FSharpPrintfFormatClassificationType() - self.ForegroundColor <- theme.GetColor FSharpClassificationTypes.Printf - - [)>] - [] - [] - [] - [] - type internal FSharpPropertyFormat() as self = - inherit ClassificationFormatDefinition() - - do self.DisplayName <- SR.FSharpPropertiesClassificationType() - - [)>] - [] - [] - [] - [] - type internal FSharpDisposableFormat [](theme: ThemeColors) as self = - inherit ClassificationFormatDefinition() - - do self.DisplayName <- SR.FSharpDisposablesClassificationType() - self.ForegroundColor <- theme.GetColor FSharpClassificationTypes.Disposable \ No newline at end of file + //[] + //let FSharpFunctionClassificationType : ClassificationTypeDefinition = null + + //[] + //let FSharpMutableVarClassificationType : ClassificationTypeDefinition = null + + //[] + //let FSharpPrintfClassificationType : ClassificationTypeDefinition = null + + //[] + //let FSharpPropertyClassificationType : ClassificationTypeDefinition = null + + //[] + //let FSharpDisposableClassificationType : ClassificationTypeDefinition = null + + //[)>] + //[] + //[] + //[] + //[] + //type internal FSharpFunctionTypeFormat() as self = + // inherit ClassificationFormatDefinition() + + // do self.DisplayName <- SR.FSharpFunctionsOrMethodsClassificationType() + + //[)>] + //[] + //[] + //[] + //[] + //type internal FSharpMutableVarTypeFormat [](theme: ThemeColors) as self = + // inherit ClassificationFormatDefinition() + + // do self.DisplayName <- SR.FSharpMutableVarsClassificationType() + // self.ForegroundColor <- theme.GetColor FSharpClassificationTypes.MutableVar + + //[)>] + //[] + //[] + //[] + //[] + //type internal FSharpPrintfTypeFormat [](theme: ThemeColors) as self = + // inherit ClassificationFormatDefinition() + + // do self.DisplayName <- SR.FSharpPrintfFormatClassificationType() + // self.ForegroundColor <- theme.GetColor FSharpClassificationTypes.Printf + + //[)>] + //[] + //[] + //[] + //[] + //type internal FSharpPropertyFormat() as self = + // inherit ClassificationFormatDefinition() + + // do self.DisplayName <- SR.FSharpPropertiesClassificationType() + + //[)>] + //[] + //[] + //[] + //[] + //type internal FSharpDisposableFormat [](theme: ThemeColors) as self = + //inherit ClassificationFormatDefinition() + + //do self.DisplayName <- SR.FSharpDisposablesClassificationType() + //self.ForegroundColor <- theme.GetColor FSharpClassificationTypes.Disposable \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddNewKeywordToDisposableConstructorInvocation.fs b/vsintegration/src/FSharp.Editor/CodeFix/AddNewKeywordToDisposableConstructorInvocation.fs index 0253a220ae7..ed979c0d216 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/AddNewKeywordToDisposableConstructorInvocation.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/AddNewKeywordToDisposableConstructorInvocation.fs @@ -19,7 +19,7 @@ type internal FSharpAddNewKeywordCodeFixProvider() = override this.RegisterCodeFixesAsync context : Task = async { - let title = SR.AddNewKeyword() + let title = "SR.AddNewKeyword()" context.RegisterCodeFix( CodeAction.Create( title, diff --git a/vsintegration/src/FSharp.Editor/CodeFix/FixIndexerAccess.fs b/vsintegration/src/FSharp.Editor/CodeFix/FixIndexerAccess.fs index eb9a49c0fad..71660a0ffc2 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/FixIndexerAccess.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/FixIndexerAccess.fs @@ -48,7 +48,8 @@ type internal FSharpFixIndexerAccessCodeFixProvider() = let codefix = CodeFixHelpers.createTextChangeCodeFix( - CompilerDiagnostics.getErrorMessage AddIndexerDot, + "Add Indexer Dot", + //CompilerDiagnostics.getErrorMessage AddIndexerDot, context, (fun () -> asyncMaybe.Return [| TextChange(span, replacement.TrimEnd() + ".") |])) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs b/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs index 8b46a80b7d9..2198d45c494 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs @@ -25,7 +25,7 @@ type internal FSharpProposeUpperCaseLabelCodeFixProvider asyncMaybe { let textChanger (originalText: string) = originalText.[0].ToString().ToUpper() + originalText.Substring(1) let! solutionChanger, originalText = SymbolHelpers.changeAllSymbolReferences(context.Document, context.Span, textChanger, projectInfoManager, checkerProvider.Checker, userOpName) - let title = CompilerDiagnostics.getErrorMessage (ReplaceWithSuggestion <| textChanger originalText) + let title = originalText// CompilerDiagnostics.getErrorMessage (ReplaceWithSuggestion <| textChanger originalText) context.RegisterCodeFix( CodeAction.Create(title, solutionChanger, title), context.Diagnostics |> Seq.filter (fun x -> fixableDiagnosticIds |> List.contains x.Id) |> Seq.toImmutableArray) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs b/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs index 245c1ff1405..c7fb2f2f5fc 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs @@ -54,7 +54,7 @@ type internal FSharpRenameParamToMatchSignature yield TextChange(textSpan, replacement) |] return changes } - let title = CompilerDiagnostics.getErrorMessage (ReplaceWithSuggestion suggestion) + let title = suggestion//CompilerDiagnostics.getErrorMessage (ReplaceWithSuggestion suggestion) let codefix = CodeFixHelpers.createTextChangeCodeFix(title, context, computeChanges) context.RegisterCodeFix(codefix, diagnostics) | _ -> () diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs b/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs index 969cfb55a16..fafc461cbde 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs @@ -59,10 +59,11 @@ type internal FSharpReplaceWithSuggestionCodeFixProvider let replacement = Keywords.QuoteIdentifierIfNeeded suggestion let codeFix = CodeFixHelpers.createTextChangeCodeFix( - CompilerDiagnostics.getErrorMessage (ReplaceWithSuggestion suggestion), + suggestion, + //CompilerDiagnostics.getErrorMessage (ReplaceWithSuggestion suggestion), context, (fun () -> asyncMaybe.Return [| TextChange(context.Span, replacement) |])) - + context.RegisterCodeFix(codeFix, diagnostics) } |> Async.Ignore diff --git a/vsintegration/src/FSharp.Editor/CodeFix/SimplifyName.fs b/vsintegration/src/FSharp.Editor/CodeFix/SimplifyName.fs index a2768640387..3c9320a5805 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/SimplifyName.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/SimplifyName.fs @@ -25,8 +25,8 @@ type internal FSharpSimplifyNameCodeFixProvider() = for diagnostic in context.Diagnostics |> Seq.filter (fun x -> x.Id = fixableDiagnosticId) do let title = match diagnostic.Properties.TryGetValue(SimplifyNameDiagnosticAnalyzer.LongIdentPropertyKey) with - | true, longIdent -> sprintf "%s '%s'" (SR.SimplifyName()) longIdent - | _ -> SR.SimplifyName() + | true, longIdent -> sprintf "%s '%s'" ("SR.SimplifyName()") longIdent + | _ -> "SR.SimplifyName()" let codefix = CodeFixHelpers.createTextChangeCodeFix(title, context, (fun () -> asyncMaybe.Return [| TextChange(context.Span, "") |])) diff --git a/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs b/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs index eaf4b541a84..859b64fc09d 100644 --- a/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs +++ b/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs @@ -6,7 +6,7 @@ open System open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor open System.ComponentModel.Composition -open Microsoft.VisualStudio.Utilities +//open Microsoft.VisualStudio.Utilities open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio open Microsoft.VisualStudio.LanguageServices diff --git a/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs b/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs index 21a70f89e2e..308a1f467c2 100644 --- a/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs +++ b/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs @@ -7,9 +7,9 @@ open System open System.Collections.Generic open System.Threading open System.Windows -open System.Windows.Controls +//open System.Windows.Controls open System.Windows.Media -open System.Windows.Media.Animation +//open System.Windows.Media.Animation open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Editor.Shared.Extensions diff --git a/vsintegration/src/FSharp.Editor/Commands/FsiCommandService.fs b/vsintegration/src/FSharp.Editor/Commands/FsiCommandService.fs index 389d50b3cba..54d0ec50ce0 100644 --- a/vsintegration/src/FSharp.Editor/Commands/FsiCommandService.fs +++ b/vsintegration/src/FSharp.Editor/Commands/FsiCommandService.fs @@ -10,10 +10,10 @@ open Microsoft.VisualStudio.Editor open Microsoft.VisualStudio.OLE.Interop open Microsoft.VisualStudio.Text.Editor open Microsoft.VisualStudio.TextManager.Interop -open Microsoft.VisualStudio.Utilities +//open Microsoft.VisualStudio.Utilities open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio.Shell.Interop -open Microsoft.VisualStudio.FSharp.Interactive +//open Microsoft.VisualStudio.FSharp.Interactive type internal FsiCommandFilter(serviceProvider: System.IServiceProvider) = diff --git a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs index 11922d0d0d0..a56305bc32a 100644 --- a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs +++ b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs @@ -13,7 +13,7 @@ open Microsoft.VisualStudio.OLE.Interop open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor open Microsoft.VisualStudio.TextManager.Interop -open Microsoft.VisualStudio.Utilities +//open Microsoft.VisualStudio.Utilities open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem open FSharp.Compiler.SourceCodeServices diff --git a/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs b/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs index ae8c5fe4fb6..e606321650d 100644 --- a/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs +++ b/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs @@ -18,7 +18,7 @@ open Microsoft.VisualStudio.FSharp.Editor.Logging open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics [] -module internal RoslynHelpers = +module RoslynHelpers = let FSharpRangeToTextSpan(sourceText: SourceText, range: range) = // Roslyn TextLineCollection is zero-based, F# range lines are one-based diff --git a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs index 09a7951e047..9695162b504 100644 --- a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs +++ b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs @@ -198,7 +198,7 @@ module internal XmlDocumentation = if not started then started <- true AppendHardLine collector - AppendOnNewLine collector (SR.ExceptionsHeader()) + AppendOnNewLine collector ("SR.ExceptionsHeader()") EnsureHardLine collector collector.Add(tagSpace " ") WriteTypeName collector exnType.Value diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.Designer.fs b/vsintegration/src/FSharp.Editor/FSharp.Editor.Designer.fs new file mode 100644 index 00000000000..31d1c209e8b --- /dev/null +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.Designer.fs @@ -0,0 +1,157 @@ + + +namespace FSharp.Editor +open System +open System.Reflection + +[] +type FSharp_Editor() = + [] + static val mutable private resourceMan:System.Resources.ResourceManager + + [] + static val mutable private resourceCulture:System.Globalization.CultureInfo + [] + static member ResourceManager + with get() : System.Resources.ResourceManager = + if System.Object.Equals((Unchecked.defaultof<_>), FSharp_Editor.resourceMan) then + let mutable (temp:System.Resources.ResourceManager) = new System.Resources.ResourceManager("FSharp.Editor.resx", (typeof).Assembly) + FSharp_Editor.resourceMan <- temp + ((FSharp_Editor.resourceMan :> obj) :?> System.Resources.ResourceManager) + + [] + member this.Culture + with get() : System.Globalization.CultureInfo = + ((FSharp_Editor.resourceCulture :> obj) :?> System.Globalization.CultureInfo) + and set(value:System.Globalization.CultureInfo) : unit = + FSharp_Editor.resourceCulture <- value + + member this.AddNewKeyword + with get() : string = + FSharp_Editor.ResourceManager.GetString("AddNewKeyword", FSharp_Editor.resourceCulture) + + member this.ImplementInterface + with get() : string = + FSharp_Editor.ResourceManager.GetString("ImplementInterface", FSharp_Editor.resourceCulture) + + member this.ImplementInterfaceWithoutTypeAnnotation + with get() : string = + FSharp_Editor.ResourceManager.GetString("ImplementInterfaceWithoutTypeAnnotation", FSharp_Editor.resourceCulture) + + member this.PrefixValueNameWithUnderscore + with get() : string = + FSharp_Editor.ResourceManager.GetString("PrefixValueNameWithUnderscore", FSharp_Editor.resourceCulture) + + member this.RenameValueToUnderscore + with get() : string = + FSharp_Editor.ResourceManager.GetString("RenameValueToUnderscore", FSharp_Editor.resourceCulture) + + member this.SimplifyName + with get() : string = + FSharp_Editor.ResourceManager.GetString("SimplifyName", FSharp_Editor.resourceCulture) + + member this.NameCanBeSimplified + with get() : string = + FSharp_Editor.ResourceManager.GetString("NameCanBeSimplified", FSharp_Editor.resourceCulture) + + member this.FSharpFunctionsOrMethodsClassificationType + with get() : string = + FSharp_Editor.ResourceManager.GetString("FSharpFunctionsOrMethodsClassificationType", FSharp_Editor.resourceCulture) + + member this.FSharpMutableVarsClassificationType + with get() : string = + FSharp_Editor.ResourceManager.GetString("FSharpMutableVarsClassificationType", FSharp_Editor.resourceCulture) + + member this.FSharpPrintfFormatClassificationType + with get() : string = + FSharp_Editor.ResourceManager.GetString("FSharpPrintfFormatClassificationType", FSharp_Editor.resourceCulture) + + member this.FSharpPropertiesClassificationType + with get() : string = + FSharp_Editor.ResourceManager.GetString("FSharpPropertiesClassificationType", FSharp_Editor.resourceCulture) + + member this.FSharpDisposablesClassificationType + with get() : string = + FSharp_Editor.ResourceManager.GetString("FSharpDisposablesClassificationType", FSharp_Editor.resourceCulture) + + member this.RemoveUnusedOpens + with get() : string = + FSharp_Editor.ResourceManager.GetString("RemoveUnusedOpens", FSharp_Editor.resourceCulture) + + member this.UnusedOpens + with get() : string = + FSharp_Editor.ResourceManager.GetString("UnusedOpens", FSharp_Editor.resourceCulture) + + //member this.6008 + // with get() : string = + // FSharp_Editor.ResourceManager.GetString("6008", FSharp_Editor.resourceCulture) + + //member this.6009 + //with get() : string = + //FSharp_Editor.ResourceManager.GetString("6009", FSharp_Editor.resourceCulture) + + member this.AddAssemblyReference + with get() : string = + FSharp_Editor.ResourceManager.GetString("AddAssemblyReference", FSharp_Editor.resourceCulture) + + member this.AddProjectReference + with get() : string = + FSharp_Editor.ResourceManager.GetString("AddProjectReference", FSharp_Editor.resourceCulture) + + //member this.6010 + // with get() : string = + // FSharp_Editor.ResourceManager.GetString("6010", FSharp_Editor.resourceCulture) + + //member this.6011 + // with get() : string = + // FSharp_Editor.ResourceManager.GetString("6011", FSharp_Editor.resourceCulture) + + //member this.6012 + // with get() : string = + // FSharp_Editor.ResourceManager.GetString("6012", FSharp_Editor.resourceCulture) + + //member this.6013 + // with get() : string = + // FSharp_Editor.ResourceManager.GetString("6013", FSharp_Editor.resourceCulture) + + //member this.6014 + //with get() : string = + //FSharp_Editor.ResourceManager.GetString("6014", FSharp_Editor.resourceCulture) + + member this.TheValueIsUnused + with get() : string = + FSharp_Editor.ResourceManager.GetString("TheValueIsUnused", FSharp_Editor.resourceCulture) + + member this.CannotDetermineSymbol + with get() : string = + FSharp_Editor.ResourceManager.GetString("CannotDetermineSymbol", FSharp_Editor.resourceCulture) + + member this.CannotNavigateUnknown + with get() : string = + FSharp_Editor.ResourceManager.GetString("CannotNavigateUnknown", FSharp_Editor.resourceCulture) + + member this.LocatingSymbol + with get() : string = + FSharp_Editor.ResourceManager.GetString("LocatingSymbol", FSharp_Editor.resourceCulture) + + member this.NavigatingTo + with get() : string = + FSharp_Editor.ResourceManager.GetString("NavigatingTo", FSharp_Editor.resourceCulture) + + member this.NavigateToFailed + with get() : string = + FSharp_Editor.ResourceManager.GetString("NavigateToFailed", FSharp_Editor.resourceCulture) + + member this.ExceptionsHeader + with get() : string = + FSharp_Editor.ResourceManager.GetString("ExceptionsHeader", FSharp_Editor.resourceCulture) + + member this.GenericParametersHeader + with get() : string = + FSharp_Editor.ResourceManager.GetString("GenericParametersHeader", FSharp_Editor.resourceCulture) + + member this.RenameValueToDoubleUnderscore + with get() : string = + FSharp_Editor.ResourceManager.GetString("RenameValueToDoubleUnderscore", FSharp_Editor.resourceCulture) \ 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 77add187654..67dc1330683 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -11,19 +11,26 @@ $(SystemValueTupleVersion) $(OtherFlags) --warnon:1182 --subsystemversion:6.00 false + net472 + + false + - - - + + + + + + + - - true - Microsoft.VisualStudio.FSharp.Editor.SR - + + + @@ -35,16 +42,13 @@ - - Common\LspExternalAccess.fs - - - - - - - - + + + + + + + @@ -54,13 +58,38 @@ + - - LanguageService\JsonOptionConverter.fs - + + + + + + + + + + + + + + + + + + + FSharp.Editor + $(VSAssemblyVersion) + $PackageFolder$\FSharp.Editor.dll + + + + + + @@ -68,11 +97,7 @@ - - - - - + @@ -89,102 +114,67 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + FSharp.Editor.resx + + + true + Microsoft.VisualStudio.FSharp.Editor.SR + PublicResXFileCodeGenerator + FSharp.Editor.Designer.fs + + + + + + + + + - - - + - - + - - - - - - - - - - - - - - + + + - - - - + + + + + Common\LspExternalAccess.fs + + + + + + + - - - - - - FSharp.Editor - $(VSAssemblyVersion) - $PackageFolder$\FSharp.Editor.dll - - - FSharp.UIResources - $(VSAssemblyVersion) - $PackageFolder$\FSharp.UIResources.dll - + + - diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs index 8397825d71a..62e31e137b4 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs @@ -57,7 +57,7 @@ type internal FSharpCheckerProvider keepAllBackgroundResolutions = false, // Enabling this would mean that if devenv.exe goes above 2.3GB we do a one-off downsize of the F# Compiler Service caches (* , MaxMemory = 2300 *) - legacyReferenceResolver=LegacyMSBuildReferenceResolver.getResolver(), + (*legacyReferenceResolver=LegacyMSBuildReferenceResolver.getResolver(),*) tryGetMetadataSnapshot = tryGetMetadataSnapshot) // This is one half of the bridge between the F# background builder and the Roslyn analysis engine. diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index f02f4e344b4..db2ccf139dd 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -91,36 +91,36 @@ type internal FSharpSettingsFactory member __.CreateService(_) = upcast settings [] -[, - "F# Tools", "F# Interactive", // category/sub-category on Tools>Options... - 6000s, 6001s, // resource id for localisation of the above - true)>] // true = supports automation -[] // <-- resource ID for localised name -[, - // The following should place the ToolWindow with the OutputWindow by default. - Orientation=ToolWindowOrientation.Bottom, - Style=VsDockStyle.Tabbed, - PositionX = 0, - PositionY = 0, - Width = 360, - Height = 120, - Window="34E76E81-EE4A-11D0-AE2E-00A0C90FFFC3")>] -[, "F#", null, "IntelliSense", "6008")>] -[, "F#", null, "QuickInfo", "6009")>] -[, "F#", null, "Code Fixes", "6010")>] -[, "F#", null, "Performance", "6011")>] -[, "F#", null, "Advanced", "6012")>] -[, "F#", null, "CodeLens", "6013")>] -[, "F#", null, "Formatting", "6014")>] -[] -// 64 represents a hex number. It needs to be greater than 37 so the TextMate editor will not be chosen as higher priority. -[, ".fs", 64)>] -[, ".fsi", 64)>] -[, ".fsscript", 64)>] -[, ".fsx", 64)>] -[, ".ml", 64)>] -[, ".mli", 64)>] -[, 101s, CommonPhysicalViewAttributes = Constants.FSharpEditorFactoryPhysicalViewAttributes)>] +//[, +// "F# Tools", "F# Interactive", // category/sub-category on Tools>Options... +// 6000s, 6001s, // resource id for localisation of the above +// true)>] // true = supports automation +//[] // <-- resource ID for localised name +//[, +// // The following should place the ToolWindow with the OutputWindow by default. +// Orientation=ToolWindowOrientation.Bottom, +// Style=VsDockStyle.Tabbed, +// PositionX = 0, +// PositionY = 0, +// Width = 360, +// Height = 120, +// Window="34E76E81-EE4A-11D0-AE2E-00A0C90FFFC3")>] +//[, "F#", null, "IntelliSense", "6008")>] +//[, "F#", null, "QuickInfo", "6009")>] +//[, "F#", null, "Code Fixes", "6010")>] +//[, "F#", null, "Performance", "6011")>] +//[, "F#", null, "Advanced", "6012")>] +//[, "F#", null, "CodeLens", "6013")>] +//[, "F#", null, "Formatting", "6014")>] +//[] +//// 64 represents a hex number. It needs to be greater than 37 so the TextMate editor will not be chosen as higher priority. +//[, ".fs", 64)>] +//[, ".fsi", 64)>] +//[, ".fsscript", 64)>] +//[, ".fsx", 64)>] +//[, ".ml", 64)>] +//[, ".mli", 64)>] +//[, 101s, CommonPhysicalViewAttributes = Constants.FSharpEditorFactoryPhysicalViewAttributes)>] [, ".fs")>] [, ".fsi")>] [, ".fsx")>] @@ -148,17 +148,17 @@ type internal FSharpSettingsFactory type internal FSharpPackage() as this = inherit AbstractPackage() - let mutable vfsiToolWindow = Unchecked.defaultof - let GetToolWindowAsITestVFSI() = - if vfsiToolWindow = Unchecked.defaultof<_> then - vfsiToolWindow <- this.FindToolWindow(typeof, 0, true) :?> Microsoft.VisualStudio.FSharp.Interactive.FsiToolWindow - vfsiToolWindow :> Microsoft.VisualStudio.FSharp.Interactive.ITestVFSI + //let mutable vfsiToolWindow = Unchecked.defaultof + //let GetToolWindowAsITestVFSI() = + //if vfsiToolWindow = Unchecked.defaultof<_> then + // vfsiToolWindow <- this.FindToolWindow(typeof, 0, true) :?> Microsoft.VisualStudio.FSharp.Interactive.FsiToolWindow + //vfsiToolWindow :> Microsoft.VisualStudio.FSharp.Interactive.ITestVFSI let mutable solutionEventsOpt = None // FSI-LINKAGE-POINT: unsited init - do - Microsoft.VisualStudio.FSharp.Interactive.Hooks.fsiConsoleWindowPackageCtorUnsited (this :> Package) + //do + //Microsoft.VisualStudio.FSharp.Interactive.Hooks.fsiConsoleWindowPackageCtorUnsited (this :> Package) override this.InitializeAsync(cancellationToken: CancellationToken, progress: IProgress) : Tasks.Task = // `base.` methods can't be called in the `async` builder, so we have to cache it @@ -167,14 +167,14 @@ type internal FSharpPackage() as this = async { do! baseInitializeAsync |> Async.AwaitTask - let! commandService = this.GetServiceAsync(typeof) |> Async.AwaitTask // FSI-LINKAGE-POINT - let commandService = commandService :?> OleMenuCommandService + //let! commandService = this.GetServiceAsync(typeof) |> Async.AwaitTask // FSI-LINKAGE-POINT + //let commandService = commandService :?> OleMenuCommandService let packageInit () = // FSI-LINKAGE-POINT: sited init - Microsoft.VisualStudio.FSharp.Interactive.Hooks.fsiConsoleWindowPackageInitalizeSited (this :> Package) commandService + //Microsoft.VisualStudio.FSharp.Interactive.Hooks.fsiConsoleWindowPackageInitalizeSited (this :> Package) commandService // FSI-LINKAGE-POINT: private method GetDialogPage forces fsi options to be loaded - let _fsiPropertyPage = this.GetDialogPage(typeof) + //let _fsiPropertyPage = this.GetDialogPage(typeof) let projectInfoManager = this.ComponentModel.DefaultExportProvider.GetExport().Value let solution = this.GetServiceAsync(typeof).Result let solution = solution :?> IVsSolution @@ -203,15 +203,15 @@ type internal FSharpPackage() as this = override this.RoslynLanguageName = FSharpConstants.FSharpLanguageName override this.CreateWorkspace() = this.ComponentModel.GetService() override this.CreateLanguageService() = FSharpLanguageService(this) - override this.CreateEditorFactories() = seq { yield FSharpEditorFactory(this) :> IVsEditorFactory } + override this.CreateEditorFactories() = this.CreateEditorFactories()// seq { yield FSharpEditorFactory(this) :> IVsEditorFactory } override this.RegisterMiscellaneousFilesWorkspaceInformation(miscFilesWorkspace) = miscFilesWorkspace.RegisterLanguage(Guid(FSharpConstants.languageServiceGuidString), FSharpConstants.FSharpLanguageName, ".fsx") - interface Microsoft.VisualStudio.FSharp.Interactive.ITestVFSI with - member this.SendTextInteraction(s:string) = - GetToolWindowAsITestVFSI().SendTextInteraction(s) - member this.GetMostRecentLines(n:int) : string[] = - GetToolWindowAsITestVFSI().GetMostRecentLines(n) + //interface Microsoft.VisualStudio.FSharp.Interactive.ITestVFSI with + //member this.SendTextInteraction(s:string) = + // GetToolWindowAsITestVFSI().SendTextInteraction(s) + //member this.GetMostRecentLines(n:int) : string[] = + //GetToolWindowAsITestVFSI().GetMostRecentLines(n) [] type internal FSharpLanguageService(package : FSharpPackage) = diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs index a1022788ab6..0d969d9ca14 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs @@ -15,7 +15,7 @@ open Microsoft.VisualStudio.Language.Intellisense open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor open Microsoft.VisualStudio.Shell.Interop -open Microsoft.VisualStudio.Utilities +//open Microsoft.VisualStudio.Utilities open Microsoft.VisualStudio.Shell [] @@ -44,8 +44,8 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider let position = triggerSpan.Start.Position let document = snapshot.GetOpenDocumentInCurrentContextWithChanges() let! sourceText = document.GetTextAsync() |> liftTaskAsync - - statusBar.Message(SR.LocatingSymbol()) + + statusBar.Message("SR.LocatingSymbol()") use _ = statusBar.Animate() let gtdTask = gtd.FindDefinitionTask(document, position, cancellationToken) @@ -66,12 +66,12 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider return FSharpNavigableSymbol(navigableItem, symbolSpan, gtd, statusBar) :> INavigableSymbol else - statusBar.TempMessage(SR.CannotDetermineSymbol()) + statusBar.TempMessage("SR.CannotDetermineSymbol()") // The NavigableSymbols API accepts 'null' when there's nothing to navigate to. return null with exc -> - statusBar.TempMessage(String.Format(SR.NavigateToFailed(), Exception.flattenMessage exc)) + statusBar.TempMessage(String.Format("SR.NavigateToFailed()", Exception.flattenMessage exc)) // The NavigableSymbols API accepts 'null' when there's nothing to navigate to. return null @@ -83,9 +83,9 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider disposed <- true [)>] -[] -[] -[] +//[] +//[] +//[] type internal FSharpNavigableSymbolService [] ( diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs index 428ca48ef62..dd6819811be 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs @@ -218,40 +218,40 @@ type internal FSharpNavigateToSearchService itemsByDocumentId.Set(cacheItem, policy) return indexedItems } - let patternMatchKindToNavigateToMatchKind = function - | PatternMatchKind.Exact -> FSharpNavigateToMatchKind.Exact - | PatternMatchKind.Prefix -> FSharpNavigateToMatchKind.Prefix - | PatternMatchKind.Substring -> FSharpNavigateToMatchKind.Substring - | PatternMatchKind.CamelCase -> FSharpNavigateToMatchKind.Regular - | PatternMatchKind.Fuzzy -> FSharpNavigateToMatchKind.Regular + let _patternMatchKindToNavigateToMatchKind = function + //| PatternMatchKind.Exact -> FSharpNavigateToMatchKind.Exact + //| PatternMatchKind.Prefix -> FSharpNavigateToMatchKind.Prefix + //| PatternMatchKind.Substring -> FSharpNavigateToMatchKind.Substring + //| PatternMatchKind.CamelCase -> FSharpNavigateToMatchKind.Regular + //| PatternMatchKind.Fuzzy -> FSharpNavigateToMatchKind.Regular | _ -> FSharpNavigateToMatchKind.Regular interface IFSharpNavigateToSearchService with - member __.SearchProjectAsync(project, _priorityDocuments, searchPattern, kinds, cancellationToken) : Task> = + member __.SearchProjectAsync(project, _priorityDocuments, _searchPattern, kinds, cancellationToken) : Task> = asyncMaybe { let! parsingOptions, _options = projectInfoManager.TryGetOptionsByProject(project, cancellationToken) - let! items = + let! _items = project.Documents |> Seq.map (fun document -> getCachedIndexedNavigableItems(document, parsingOptions, kinds)) |> Async.Parallel |> liftAsync - - let items = - if searchPattern.Length = 1 then - items - |> Array.map (fun items -> items.Find(searchPattern)) - |> Array.concat - |> Array.filter (fun x -> x.Name.Length = 1 && String.Equals(x.Name, searchPattern, StringComparison.InvariantCultureIgnoreCase)) - else - [| yield! items |> Array.map (fun items -> items.Find(searchPattern)) |> Array.concat - use patternMatcher = new PatternMatcher(searchPattern, allowFuzzyMatching = true) - yield! items - |> Array.collect (fun item -> item.AllItems) - |> Array.Parallel.collect (fun x -> - patternMatcher.GetMatches(x.Name) - |> Seq.map (fun pm -> - NavigateToSearchResult(x, patternMatchKindToNavigateToMatchKind pm.Kind) :> FSharpNavigateToSearchResult) - |> Seq.toArray) |] + + let items = Array.Empty() + //if searchPattern.Length = 1 then + // items + // |> Array.map (fun items -> items.Find(searchPattern)) + // |> Array.concat + // |> Array.filter (fun x -> x.Name.Length = 1 && String.Equals(x.Name, searchPattern, StringComparison.InvariantCultureIgnoreCase)) + //else + //[| yield! items |> Array.map (fun items -> items.Find(searchPattern)) |> Array.concat + //use patternMatcher = new PatternMatcher(searchPattern, allowFuzzyMatching = true) + //yield! items + //|> Array.collect (fun item -> item.AllItems) + //|> Array.Parallel.collect (fun x -> + //patternMatcher.GetMatches(x.Name) + //|> Seq.map (fun pm -> + // NavigateToSearchResult(x, patternMatchKindToNavigateToMatchKind pm.Kind) :> FSharpNavigateToSearchResult) + //|> Seq.toArray) |] return items |> Array.distinctBy (fun x -> x.NavigableItem.Document.Id, x.NavigableItem.SourceSpan) } diff --git a/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs b/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs new file mode 100644 index 00000000000..f1cc8a6d751 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs @@ -0,0 +1,140 @@ +namespace Microsoft.VisualStudio.FSharp.Editor +open System +open System.ComponentModel.Composition + +module DefaultTuning = + let UnusedDeclarationsAnalyzerInitialDelay = 0 (* 1000 *) (* milliseconds *) + let UnusedOpensAnalyzerInitialDelay = 0 (* 2000 *) (* milliseconds *) + let SimplifyNameInitialDelay = 2000 (* milliseconds *) + let SimplifyNameEachItemDelay = 0 (* milliseconds *) + + /// How long is the per-document data saved before it is eligible for eviction from the cache? 10 seconds. + /// Re-tokenizing is fast so we don't need to save this data long. + let PerDocumentSavedDataSlidingWindow = TimeSpan(0,0,10)(* seconds *) + +type EnterKeySetting = + | NeverNewline + | NewlineOnCompleteWord + | AlwaysNewline + +// CLIMutable to make the record work also as a view model +[] +type IntelliSenseOptions = + { ShowAfterCharIsTyped: bool + ShowAfterCharIsDeleted: bool + IncludeSymbolsFromUnopenedNamespacesOrModules : bool + EnterKeySetting : EnterKeySetting } + static member Default = + { ShowAfterCharIsTyped = true + ShowAfterCharIsDeleted = false + IncludeSymbolsFromUnopenedNamespacesOrModules = false + EnterKeySetting = EnterKeySetting.NeverNewline} + + +[] +type QuickInfoUnderlineStyle = Dot | Dash | Solid + +[] +type QuickInfoOptions = + { DisplayLinks: bool + UnderlineStyle: QuickInfoUnderlineStyle } + static member Default = + { DisplayLinks = true + UnderlineStyle = QuickInfoUnderlineStyle.Solid } + +[] +type CodeFixesOptions = + { SimplifyName: bool + AlwaysPlaceOpensAtTopLevel: bool + UnusedOpens: bool + UnusedDeclarations: bool + SuggestNamesForErrors: bool } + static member Default = + { // We have this off by default, disable until we work out how to make this low priority + // See https://github.com/Microsoft/visualfsharp/pull/3238#issue-237699595 + SimplifyName = false + AlwaysPlaceOpensAtTopLevel = true + UnusedOpens = true + UnusedDeclarations = true + SuggestNamesForErrors = true } + +[] +type LanguageServicePerformanceOptions = + { EnableInMemoryCrossProjectReferences: bool + AllowStaleCompletionResults: bool + TimeUntilStaleCompletion: int + ProjectCheckCacheSize: int } + static member Default = + { EnableInMemoryCrossProjectReferences = true + AllowStaleCompletionResults = true + TimeUntilStaleCompletion = 2000 // In ms, so this is 2 seconds + ProjectCheckCacheSize = 200 } + +[] +type CodeLensOptions = + { Enabled : bool + ReplaceWithLineLens: bool + UseColors: bool + Prefix : string } + static member Default = + { Enabled = false + UseColors = false + ReplaceWithLineLens = true + Prefix = "// " } + +[] +type AdvancedOptions = + { IsBlockStructureEnabled: bool + IsOutliningEnabled: bool + UsePreviewTextHover: bool } + static member Default = + { IsBlockStructureEnabled = true + IsOutliningEnabled = true + UsePreviewTextHover = false } + +[] +type FormattingOptions = + { FormatOnPaste: bool } + static member Default = + { FormatOnPaste = true } + + +[] +[)>] +type EditorOptions + [] + ( + //[)>] serviceProvider: IServiceProvider + ) = + + //let c = MonoDevelop.Ide.Composition.CompositionManager. + let store = SettingsStore((*serviceProvider*)) + + do + store.Register QuickInfoOptions.Default + store.Register CodeFixesOptions.Default + store.Register LanguageServicePerformanceOptions.Default + store.Register AdvancedOptions.Default + store.Register IntelliSenseOptions.Default + store.Register CodeLensOptions.Default + store.Register FormattingOptions.Default + + member __.IntelliSense : IntelliSenseOptions = store.Get() + member __.QuickInfo : QuickInfoOptions = store.Get() + member __.CodeFixes : CodeFixesOptions = store.Get() + member __.LanguageServicePerformance : LanguageServicePerformanceOptions = store.Get() + member __.Advanced: AdvancedOptions = store.Get() + member __.CodeLens: CodeLensOptions = store.Get() + member __.Formatting : FormattingOptions = store.Get() + + interface Microsoft.CodeAnalysis.Host.IWorkspaceService + + interface IPersistSettings with + member __.LoadSettings() = store.LoadSettings() + member __.SaveSettings(settings) = store.SaveSettings(settings) + +[] +module internal WorkspaceSettingFromDocumentExtension = + type Microsoft.CodeAnalysis.Document with + member this.FSharpOptions = + this.Project.Solution.Workspace.Services.GetService() : EditorOptions diff --git a/vsintegration/src/FSharp.Editor/Options/SettingsPersistence.fs b/vsintegration/src/FSharp.Editor/Options/SettingsPersistence.fs index 096aebc9544..febc6764f9b 100644 --- a/vsintegration/src/FSharp.Editor/Options/SettingsPersistence.fs +++ b/vsintegration/src/FSharp.Editor/Options/SettingsPersistence.fs @@ -15,17 +15,17 @@ type IPersistSettings = [] type SVsSettingsPersistenceManager = class end -type SettingsStore(serviceProvider: IServiceProvider) = +type SettingsStore((*serviceProvider: IServiceProvider*)) = - let settingsManager = serviceProvider.GetService(typeof) :?> ISettingsManager + //let settingsManager = serviceProvider.GetService(typeof) :?> ISettingsManager - let storageKeyVersions (typ: Type) = - // "TextEditor" prefix seems to be required for settings changes to be synced between IDE instances - [ "TextEditor.FSharp." + typ.Namespace + "." + typ.Name - // we keep this old storage key to upgrade without reverting user changes - typ.Namespace + "." + typ.Name ] + //let storageKeyVersions (typ: Type) = + //// "TextEditor" prefix seems to be required for settings changes to be synced between IDE instances + //[ "TextEditor.FSharp." + typ.Namespace + "." + typ.Name + //// we keep this old storage key to upgrade without reverting user changes + //typ.Namespace + "." + typ.Name ] - let storageKey (typ: Type) = storageKeyVersions typ |> List.head + //let storageKey (typ: Type) = storageKeyVersions typ |> List.head // Each group of settings is a value of some named type, for example 'IntelliSenseOptions', 'QuickInfoOptions' // and it is usually representing one separate option page in the UI. @@ -39,7 +39,7 @@ type SettingsStore(serviceProvider: IServiceProvider) = | true, (:? 't as value) -> value | _ -> failwithf "Settings %s are not registered." typeof<'t>.Name - let keepInCache settings = cache.[settings.GetType()] <- settings + //let keepInCache settings = cache.[settings.GetType()] <- settings // The settings record, even though immutable, is being effectively mutated in two instances: // when it is passed to the UI (provided it is marked with CLIMutable attribute); @@ -47,16 +47,16 @@ type SettingsStore(serviceProvider: IServiceProvider) = // We make a deep copy in these instances to isolate and contain the mutation let clone (v: 't) = JsonConvert.SerializeObject v |> JsonConvert.DeserializeObject<'t> - let updateFromStore settings = - // make a deep copy so that PopulateObject does not alter the original - let copy = clone settings - // if the new key is not found by ISettingsManager, we try the old keys - // so that user settings are not lost - settings.GetType() |> storageKeyVersions - |> Seq.map (settingsManager.TryGetValue) - |> Seq.tryPick ( function GetValueResult.Success, json -> Some json | _ -> None ) - |> Option.iter (fun json -> try JsonConvert.PopulateObject(json, copy) with _ -> ()) - copy + //let updateFromStore settings = + //// make a deep copy so that PopulateObject does not alter the original + //let copy = clone settings + //// if the new key is not found by ISettingsManager, we try the old keys + //// so that user settings are not lost + //settings.GetType() |> storageKeyVersions + //|> Seq.map (settingsManager.TryGetValue) + //|> Seq.tryPick ( function GetValueResult.Success, json -> Some json | _ -> None ) + //|> Option.iter (fun json -> try JsonConvert.PopulateObject(json, copy) with _ -> ()) + //copy member __.Get() = getCached() @@ -65,20 +65,22 @@ type SettingsStore(serviceProvider: IServiceProvider) = // cloned value here because it may be altered by the UI if declared with [] member __.LoadSettings() = getCached() |> clone - member __.SaveSettings settings = - // We replace default serialization with Newtonsoft.Json for easy schema evolution. - // For example, if we add a new bool field to the record, representing another checkbox in Options dialog - // deserialization will still work fine. When we pass default value to JsonConvert.PopulateObject it will - // fill just the known fields. - settingsManager.SetValueAsync(settings.GetType() |> storageKey, JsonConvert.SerializeObject settings, false) - |> Async.AwaitTask |> Async.Start + member __.SaveSettings _settings = + //// We replace default serialization with Newtonsoft.Json for easy schema evolution. + //// For example, if we add a new bool field to the record, representing another checkbox in Options dialog + //// deserialization will still work fine. When we pass default value to JsonConvert.PopulateObject it will + //// fill just the known fields. + //settingsManager.SetValueAsync(settings.GetType() |> storageKey, JsonConvert.SerializeObject settings, false) + //|> Async.AwaitTask |> Async.Start + () // This is the point we retrieve the initial value and subscribe to watch for changes - member __.Register (defaultSettings : 'options) = - defaultSettings |> updateFromStore |> keepInCache - let subset = defaultSettings.GetType() |> storageKey |> settingsManager.GetSubset - // this event is also raised when a setting change occurs in another VS instance, so we can keep everything in sync - PropertyChangedAsyncEventHandler ( fun _ _ -> - (getCached(): 'options) |> updateFromStore |> keepInCache - System.Threading.Tasks.Task.CompletedTask ) - |> subset.add_SettingChangedAsync + member __.Register (_defaultSettings : 'options) = + //defaultSettings |> updateFromStore |> keepInCache + //let subset = defaultSettings.GetType() |> storageKey |> settingsManager.GetSubset + //// this event is also raised when a setting change occurs in another VS instance, so we can keep everything in sync + //PropertyChangedAsyncEventHandler ( fun _ _ -> + // (getCached(): 'options) |> updateFromStore |> keepInCache + // System.Threading.Tasks.Task.CompletedTask ) + //|> subset.add_SettingChangedAsync + () diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index 7b90bb3aefc..d75971c53ce 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -15,7 +15,7 @@ open Microsoft.VisualStudio.Language.Intellisense open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.Text -open Microsoft.VisualStudio.Utilities +//open Microsoft.VisualStudio.Utilities open FSharp.Compiler.SourceCodeServices open FSharp.Compiler.Range @@ -266,9 +266,9 @@ type internal FSharpAsyncQuickInfoSource |> RoslynHelpers.StartAsyncAsTask cancellationToken [)>] -[] -[] -[] +//[] +//[] +//[] type internal FSharpAsyncQuickInfoSourceProvider [] ( diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs b/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs index f560382b34a..b38d6d3186f 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs @@ -5,11 +5,11 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System open System.ComponentModel.Composition open System.Windows -open System.Windows.Controls +//open System.Windows.Controls open Microsoft.VisualStudio.Text.Adornments open Microsoft.VisualStudio.Text.Editor -open Microsoft.VisualStudio.Utilities +//open Microsoft.VisualStudio.Utilities [)>] [] @@ -59,5 +59,5 @@ type WpfNavigableTextRunViewElementFactory | _ -> () // add navigation - convertedElement.MouseDown.Add(fun _ -> navigableTextRun.NavigateAction()) + //convertedElement.MouseDown.Add(fun _ -> navigableTextRun.NavigateAction()) convertedElement :> obj :?> 'TView From c7ea713ef7b8e82eea22decae733ecd9ec0f560f Mon Sep 17 00:00:00 2001 From: nosami Date: Sat, 30 Nov 2019 00:42:54 +0000 Subject: [PATCH 002/101] Remove VS SDK tools --- eng/Versions.props | 8 ++++---- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 6f8ef30d19b..948f10cf498 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -4,10 +4,10 @@ false true - true - true - true - true + + + + diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 67dc1330683..a598bfde4b7 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -140,12 +140,12 @@ FSharp.Editor.Designer.fs - + - + @@ -173,7 +173,7 @@ - + From e3fbbeb32f7f525feb65778352f69b3bcd4fad91 Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 10 Dec 2019 19:58:21 +0000 Subject: [PATCH 003/101] Better tooltips --- vsintegration/src/Directory.Build.props | 2 +- .../BraceCompletionSessionProvider.fs | 4 +- .../ClassificationDefinitions.fs | 42 +- .../CodeLens/CodeLensProvider.fs | 19 +- .../Commands/XmlDocCommandService.fs | 4 +- .../src/FSharp.Editor/Common/AssemblyInfo.fs | 6 +- .../src/FSharp.Editor/Common/Constants.fs | 2 +- .../src/FSharp.Editor/Common/Logging.fs | 39 +- .../src/FSharp.Editor/Common/RoslynHelpers.fs | 1 + .../Completion/CompletionProvider.fs | 12 +- .../Completion/CompletionService.fs | 41 +- .../FSharp.Editor/Completion/SignatureHelp.fs | 4 +- .../DocComments/XMLDocumentation.fs | 60 +-- .../src/FSharp.Editor/FSharp.Editor.fsproj | 128 +++--- .../src/FSharp.Editor/FSharp.addin.xml | 26 ++ .../LanguageService/FSharpCheckerProvider.fs | 40 +- .../FSharpProjectOptionsManager.fs | 160 ++++---- .../LanguageService/LanguageService.fs | 340 ++++++++-------- .../Navigation/GoToDefinition.fs | 8 +- .../Navigation/GoToDefinitionService.fs | 2 +- .../Navigation/NavigableSymbolsService.fs | 8 +- .../FSharp.Editor/Options/EditorOptionsMac.fs | 5 +- .../Options/SettingsPersistence.fs | 15 +- .../Project/CompilerArguments.fs | 367 ++++++++++++++++++ .../FSharp.Editor/Project/FSharpProject.fs | 348 +++++++++++++++++ .../src/FSharp.Editor/Properties/AddinInfo.fs | 17 + .../QuickInfo/QuickInfoProvider.fs | 24 +- 27 files changed, 1275 insertions(+), 449 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/FSharp.addin.xml create mode 100644 vsintegration/src/FSharp.Editor/Project/CompilerArguments.fs create mode 100644 vsintegration/src/FSharp.Editor/Project/FSharpProject.fs create mode 100644 vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs diff --git a/vsintegration/src/Directory.Build.props b/vsintegration/src/Directory.Build.props index f7a21adf80c..8256f7b79da 100644 --- a/vsintegration/src/Directory.Build.props +++ b/vsintegration/src/Directory.Build.props @@ -5,7 +5,7 @@ false false - true + false false diff --git a/vsintegration/src/FSharp.Editor/AutomaticCompletion/BraceCompletionSessionProvider.fs b/vsintegration/src/FSharp.Editor/AutomaticCompletion/BraceCompletionSessionProvider.fs index 3ad729fc4a3..dd3be821094 100644 --- a/vsintegration/src/FSharp.Editor/AutomaticCompletion/BraceCompletionSessionProvider.fs +++ b/vsintegration/src/FSharp.Editor/AutomaticCompletion/BraceCompletionSessionProvider.fs @@ -12,7 +12,7 @@ open Microsoft.VisualStudio.Text.BraceCompletion open Microsoft.VisualStudio.Text.Operations open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor -//open Microsoft.VisualStudio.Utilities +open Microsoft.VisualStudio.Utilities open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.Host @@ -504,7 +504,7 @@ type EditorBraceCompletionSessionFactory() = null [)>] -//[] +[] [] [] [] diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs index 9e995c44a9a..23e72a35629 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs @@ -8,7 +8,7 @@ open System.Windows.Media open Microsoft.VisualStudio open Microsoft.VisualStudio.Editor -open Microsoft.VisualStudio.PlatformUI +//open Microsoft.VisualStudio.PlatformUI open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio.Shell.Interop open Microsoft.Internal.VisualStudio.Shell.Interop @@ -59,7 +59,7 @@ module internal ClassificationDefinitions = type internal ThemeColors [] ( - classificationformatMapService: IClassificationFormatMapService, + //classificationformatMapService: IClassificationFormatMapService, //classificationTypeRegistry: IClassificationTypeRegistryService, [)>] serviceProvider: IServiceProvider ) = @@ -87,25 +87,25 @@ module internal ClassificationDefinitions = fontAndColorCacheManager.CheckCache( ref DefGuidList.guidTextEditorFontCategory) |> ignore fontAndColorStorage.OpenCategory(ref DefGuidList.guidTextEditorFontCategory, uint32 __FCSTORAGEFLAGS.FCSF_READONLY) |> ignore - let formatMap = classificationformatMapService.GetClassificationFormatMap(category = "text") - try - formatMap.BeginBatchUpdate() - //for ctype, (light, dark) in colorData do - //// we don't touch the changes made by the user - //if fontAndColorStorage.GetItem(ctype, Array.zeroCreate 1) <> VSConstants.S_OK then - //let ict = classificationTypeRegistry.GetClassificationType(ctype) - //let oldProps = formatMap.GetTextProperties(ict) - //let newProps = oldProps //match getCurrentThemeId() with - // //| LightTheme -> oldProps.SetForeground light - // //| DarkTheme -> oldProps.SetForeground dark - // //| UnknownTheme -> oldProps - //formatMap.SetTextProperties(ict, newProps) - fontAndColorStorage.CloseCategory() |> ignore - finally formatMap.EndBatchUpdate() - - let handler = ThemeChangedEventHandler setColors - do VSColorTheme.add_ThemeChanged handler - interface IDisposable with member __.Dispose() = VSColorTheme.remove_ThemeChanged handler + // let formatMap = classificationformatMapService.GetClassificationFormatMap(category = "text") + // try + // formatMap.BeginBatchUpdate() + // //for ctype, (light, dark) in colorData do + // //// we don't touch the changes made by the user + // //if fontAndColorStorage.GetItem(ctype, Array.zeroCreate 1) <> VSConstants.S_OK then + // //let ict = classificationTypeRegistry.GetClassificationType(ctype) + // //let oldProps = formatMap.GetTextProperties(ict) + // //let newProps = oldProps //match getCurrentThemeId() with + // // //| LightTheme -> oldProps.SetForeground light + // // //| DarkTheme -> oldProps.SetForeground dark + // // //| UnknownTheme -> oldProps + // //formatMap.SetTextProperties(ict, newProps) + // fontAndColorStorage.CloseCategory() |> ignore + // finally formatMap.EndBatchUpdate() + + //let handler = ThemeChangedEventHandler setColors + //do VSColorTheme.add_ThemeChanged handler + interface IDisposable with member __.Dispose() = ()// VSColorTheme.remove_ThemeChanged handler member __.GetColor(_ctype) = //let light, dark = colorData |> Map.ofList |> Map.find ctype diff --git a/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs b/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs index 859b64fc09d..e44fb978c05 100644 --- a/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs +++ b/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs @@ -6,14 +6,16 @@ open System open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor open System.ComponentModel.Composition -//open Microsoft.VisualStudio.Utilities -open Microsoft.VisualStudio.Shell +open Microsoft.VisualStudio.Utilities +//open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio open Microsoft.VisualStudio.LanguageServices open Microsoft.VisualStudio.Text.Tagging open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.Shared.Utilities +open MonoDevelop.Ide +open MonoDevelop.Ide.TypeSystem -[)>] +[)>] [)>] [)>] [] @@ -21,7 +23,7 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.Shared.Utilities type internal CodeLensProvider [] ( - [)>] serviceProvider: IServiceProvider, + //[)>] serviceProvider: IServiceProvider, textDocumentFactory: ITextDocumentFactoryService, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, @@ -31,8 +33,9 @@ type internal CodeLensProvider let lineLensProvider = ResizeArray() let taggers = ResizeArray() - let componentModel = Package.GetGlobalService(typeof) :?> ComponentModelHost.IComponentModel - let workspace = componentModel.GetService() + //let componentModel = Package.GetGlobalService(typeof) :?> ComponentModelHost.IComponentModel + //let workspace = componentModel.GetService() + let workspace = IdeApp.TypeSystemService.Workspace :?> MonoDevelopWorkspace /// Returns an provider for the textView if already one has been created. Else create one. let addCodeLensProviderOnce wpfView buffer = @@ -90,14 +93,14 @@ type internal CodeLensProvider if settings.CodeLens.Enabled && not settings.CodeLens.ReplaceWithLineLens then let wpfView = match view with - | :? IWpfTextView as view -> view + | :? ICocoaTextView as view -> view | _ -> failwith "error" box(addCodeLensProviderOnce wpfView buffer) :?> _ else null - interface IWpfTextViewCreationListener with + interface ICocoaTextViewCreationListener with override __.TextViewCreated view = if settings.CodeLens.Enabled && settings.CodeLens.ReplaceWithLineLens then addLineLensProviderOnce view (view.TextBuffer) |> ignore \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs index a56305bc32a..962354227af 100644 --- a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs +++ b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs @@ -19,7 +19,7 @@ open FSharp.Compiler.SourceCodeServices type internal XmlDocCommandFilter ( - wpfTextView: IWpfTextView, + wpfTextView: ICocoaTextView, filePath: string, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, @@ -126,7 +126,7 @@ type internal XmlDocCommandFilterProvider workspace: VisualStudioWorkspaceImpl, textDocumentFactoryService: ITextDocumentFactoryService, editorFactory: IVsEditorAdaptersFactoryService) = - interface IWpfTextViewCreationListener with + interface ICocoaTextViewCreationListener with member __.TextViewCreated(textView) = match editorFactory.GetViewAdapter(textView) with | null -> () diff --git a/vsintegration/src/FSharp.Editor/Common/AssemblyInfo.fs b/vsintegration/src/FSharp.Editor/Common/AssemblyInfo.fs index 124f3de404c..e1a222bc412 100644 --- a/vsintegration/src/FSharp.Editor/Common/AssemblyInfo.fs +++ b/vsintegration/src/FSharp.Editor/Common/AssemblyInfo.fs @@ -2,10 +2,10 @@ namespace Microsoft.VisualStudio.FSharp.Editor -open Microsoft.VisualStudio.Shell +//open Microsoft.VisualStudio.Shell // This is needed to load XAML resource dictionaries from FSharp.UIResources assembly because ProvideCodeBase attribute does not work for that purpose. // This adds $PackageFolder$ to the directories probed for assemblies to load. // The attribute is inexplicably class-targeted, hence the dummy class. -[] -type private BindingPathForUIResources = class end +//[] +//type private BindingPathForUIResources = class end diff --git a/vsintegration/src/FSharp.Editor/Common/Constants.fs b/vsintegration/src/FSharp.Editor/Common/Constants.fs index 2c6e7c58fdc..0323cd11862 100644 --- a/vsintegration/src/FSharp.Editor/Common/Constants.fs +++ b/vsintegration/src/FSharp.Editor/Common/Constants.fs @@ -29,7 +29,7 @@ module internal FSharpConstants = [] /// "F#" - let FSharpContentTypeName = "F#" + let FSharpContentTypeName = "code++.F#" [] /// ".fs" diff --git a/vsintegration/src/FSharp.Editor/Common/Logging.fs b/vsintegration/src/FSharp.Editor/Common/Logging.fs index cc37f948f42..2ecb2d6a8ac 100644 --- a/vsintegration/src/FSharp.Editor/Common/Logging.fs +++ b/vsintegration/src/FSharp.Editor/Common/Logging.fs @@ -28,21 +28,23 @@ module Config = open Config type [] Logger [] - ([)>] serviceProvider: IServiceProvider) = - let outputWindow = serviceProvider.GetService() |> Option.ofObj + //([)>] serviceProvider: IServiceProvider) = + () = + //let outputWindow = serviceProvider.GetService() |> Option.ofObj - let createPane () = - outputWindow |> Option.iter (fun x -> - x.CreatePane(ref fsharpOutputGuid,"F# Language Service", Convert.ToInt32 true, Convert.ToInt32 false) |> ignore) + let createPane () = () + //outputWindow |> Option.iter (fun x -> + //x.CreatePane(ref fsharpOutputGuid,"F# Language Service", Convert.ToInt32 true, Convert.ToInt32 false) |> ignore) do createPane () let getPane () = - match outputWindow |> Option.map (fun x -> x.GetPane (ref fsharpOutputGuid)) with - | Some (0, pane) -> - pane.Activate() |> ignore - Some pane - | _ -> None + //match outputWindow |> Option.map (fun x -> x.GetPane (ref fsharpOutputGuid)) with + //| Some (0, pane) -> + // pane.Activate() |> ignore + // Some pane + //| _ -> None + None static let mutable globalServiceProvider: IServiceProvider option = None @@ -62,18 +64,21 @@ type [] Logger [] member self.Log (msgType:LogType,msg:string) = let time = DateTime.Now.ToString("hh:mm:ss tt") match self.FSharpLoggingPane, msgType with - | None, _ -> () - | Some pane, LogType.Message -> String.Format("[F#][{0}{1}] {2}{3}", "" , time, msg, Environment.NewLine) |> pane.OutputString |> ignore - | Some pane, LogType.Info -> String.Format("[F#][{0}{1}] {2}{3}", "INFO " , time, msg, Environment.NewLine) |> pane.OutputString |> ignore - | Some pane, LogType.Warn -> String.Format("[F#][{0}{1}] {2}{3}", "WARN " , time, msg, Environment.NewLine) |> pane.OutputString |> ignore - | Some pane, LogType.Error -> String.Format("[F#][{0}{1}] {2}{3}", "ERROR ", time, msg, Environment.NewLine) |> pane.OutputString |> ignore - + | None, _ -> MonoDevelop.Core.LoggingService.LogDebug msg + //| Some pane, LogType.Message -> String.Format("[F#][{0}{1}] {2}{3}", "" , time, msg, Environment.NewLine) |> pane.OutputString |> ignore + //| Some pane, LogType.Info -> String.Format("[F#][{0}{1}] {2}{3}", "INFO " , time, msg, Environment.NewLine) |> pane.OutputString |> ignore + //| Some pane, LogType.Warn -> String.Format("[F#][{0}{1}] {2}{3}", "WARN " , time, msg, Environment.NewLine) |> pane.OutputString |> ignore + //| Some pane, LogType.Error -> String.Format("[F#][{0}{1}] {2}{3}", "ERROR ", time, msg, Environment.NewLine) |> pane.OutputString |> ignore + | Some _pane, LogType.Message -> String.Format("[F#][{0}{1}] {2}{3}", "" , time, msg, Environment.NewLine) |> printf "%s" + | Some _pane, LogType.Info -> String.Format("[F#][{0}{1}] {2}{3}", "INFO " , time, msg, Environment.NewLine) |> printf "%s" + | Some _pane, LogType.Warn -> String.Format("[F#][{0}{1}] {2}{3}", "WARN " , time, msg, Environment.NewLine) |> printf "%s" + | Some _pane, LogType.Error -> String.Format("[F#][{0}{1}] {2}{3}", "ERROR ", time, msg, Environment.NewLine) |> printf "%s" [] module Logging = let inline debug msg = Printf.kprintf Debug.WriteLine msg - let private logger = lazy Logger(Logger.GlobalServiceProvider) + let private logger = lazy Logger((*Logger.GlobalServiceProvider*)) let private log logType msg = logger.Value.Log(logType,msg) let logMsg msg = log LogType.Message msg diff --git a/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs b/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs index e606321650d..1871354ba59 100644 --- a/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs +++ b/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs @@ -117,6 +117,7 @@ module RoslynHelpers = tcs.TrySetCanceled(cancellationToken) |> ignore | exn -> System.Diagnostics.Trace.WriteLine("Visual F# Tools: exception swallowed and not passed to Roslyn: {0}", exn.Message) + System.Diagnostics.Trace.WriteLine(exn.StackTrace) let res = Unchecked.defaultof<_> tcs.TrySetResult(res) |> ignore ), diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index 9ec89f069dd..3d57ba59ac5 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -25,7 +25,7 @@ module Logger = Microsoft.VisualStudio.FSharp.Editor.Logger type internal FSharpCompletionProvider ( workspace: Workspace, - serviceProvider: SVsServiceProvider, + //serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider @@ -57,7 +57,7 @@ type internal FSharpCompletionProvider let settings: EditorOptions = workspace.Services.GetService() - let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder(serviceProvider.XMLMemberIndexService) + //let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder(serviceProvider.XMLMemberIndexService) static let noCommitOnSpaceRules = // These are important. They make sure we don't _commit_ autocompletion when people don't expect them to. Some examples: @@ -237,12 +237,12 @@ type internal FSharpCompletionProvider | true, completionItemIndexStr -> let completionItemIndex = int completionItemIndexStr if completionItemIndex < declarationItems.Length then - let declarationItem = declarationItems.[completionItemIndex] - let! description = declarationItem.StructuredDescriptionTextAsync + //let declarationItem = declarationItems.[completionItemIndex] + //let! description = declarationItem.StructuredDescriptionTextAsync let documentation = List() - let collector = RoslynHelpers.CollectTaggedText documentation + //let collector = RoslynHelpers.CollectTaggedText documentation // mix main description and xmldoc by using one collector - XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, collector, collector, collector, description) + //XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, collector, collector, collector, description) return CompletionDescription.Create(documentation.ToImmutableArray()) else return CompletionDescription.Empty diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index 6303e2498d2..c8de0d91dae 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -16,7 +16,7 @@ open Microsoft.VisualStudio.Shell type internal FSharpCompletionService ( workspace: Workspace, - serviceProvider: SVsServiceProvider, + //serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider, @@ -26,7 +26,7 @@ type internal FSharpCompletionService let builtInProviders = ImmutableArray.Create( - FSharpCompletionProvider(workspace, serviceProvider, checkerProvider, projectInfoManager, assemblyContentProvider), + FSharpCompletionProvider(workspace, (*serviceProvider,*) checkerProvider, projectInfoManager, assemblyContentProvider), FSharpCommonCompletionProvider.Create( HashDirectiveCompletionProvider(workspace, projectInfoManager, [ Completion.Create("""\s*#load\s+(@?"*(?"[^"]*"?))""", [".fs"; ".fsx"], useIncludeDirectives = true) @@ -47,19 +47,40 @@ type internal FSharpCompletionService .WithDismissIfLastCharacterDeleted(true) .WithDefaultEnterKeyRule(enterKeyRule) + +//[] +//[, FSharpConstants.FSharpLanguageName)>] +//type internal FSharpCompletionServiceFactory + //[] + //( + // //serviceProvider: SVsServiceProvider, + // checkerProvider: FSharpCheckerProvider + + //) + + //member x.TR = 1 + //interface ILanguageServiceFactory with + //member this.CreateLanguageService(hostLanguageServices: HostLanguageServices) : ILanguageService = + //upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, projectInfoManager, assemblyContentProvider, settings) + ////upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, new FSharpProjectOptionsManager(, assemblyContentProvider, settings) + + [] [, FSharpConstants.FSharpLanguageName)>] type internal FSharpCompletionServiceFactory [] ( - serviceProvider: SVsServiceProvider, - checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager, - assemblyContentProvider: AssemblyContentProvider, - settings: EditorOptions + //serviceProvider: SVsServiceProvider, + _checkerProvider: FSharpCheckerProvider + + //projectInfoManager: FSharpProjectOptionsManager, + //assemblyContentProvider: AssemblyContentProvider, + //settings: EditorOptions ) = - interface ILanguageServiceFactory with - member this.CreateLanguageService(hostLanguageServices: HostLanguageServices) : ILanguageService = - upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, serviceProvider, checkerProvider, projectInfoManager, assemblyContentProvider, settings) + member x.X = 1 + //interface ILanguageServiceFactory with + //member this.CreateLanguageService(hostLanguageServices: HostLanguageServices) : ILanguageService = + //upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, projectInfoManager, assemblyContentProvider, settings) + ////upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, new FSharpProjectOptionsManager(, assemblyContentProvider, settings) diff --git a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs index cde4f1d22dd..460e39d1575 100644 --- a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs +++ b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs @@ -24,13 +24,13 @@ open FSharp.Compiler.SourceCodeServices type internal FSharpSignatureHelpProvider [] ( - serviceProvider: SVsServiceProvider, + //serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager ) = static let userOpName = "SignatureHelpProvider" - let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder(serviceProvider.XMLMemberIndexService) + let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder((*serviceProvider.XMLMemberIndexService*)) static let oneColAfter (lp: LinePosition) = LinePosition(lp.Line,lp.Character+1) static let oneColBefore (lp: LinePosition) = LinePosition(lp.Line,max 0 (lp.Character-1)) diff --git a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs index 9695162b504..5a1ba0b6a51 100644 --- a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs +++ b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs @@ -212,25 +212,25 @@ module internal XmlDocumentation = let vsToken = VsThreadToken() /// Provide Xml Documentation - type Provider(xmlIndexService:IVsXMLMemberIndexService) = + type Provider((*xmlIndexService:IVsXMLMemberIndexService*)) = /// Index of assembly name to xml member index. - let cache = Dictionary() + //let cache = Dictionary() - do Events.SolutionEvents.OnAfterCloseSolution.Add (fun _ -> cache.Clear()) + //do Events.SolutionEvents.OnAfterCloseSolution.Add (fun _ -> cache.Clear()) /// Retrieve the pre-existing xml index or None - let GetMemberIndexOfAssembly(assemblyName) = - match cache.TryGetValue(assemblyName) with - | true, memberIndex -> Some(memberIndex) - | false, _ -> - let ok,memberIndex = xmlIndexService.CreateXMLMemberIndex(assemblyName) - if Com.Succeeded(ok) then - let ok = memberIndex.BuildMemberIndex() - if Com.Succeeded(ok) then - cache.Add(assemblyName, memberIndex) - Some(memberIndex) - else None - else None + //let GetMemberIndexOfAssembly(assemblyName) = + //match cache.TryGetValue(assemblyName) with + //| true, memberIndex -> Some(memberIndex) + //| false, _ -> + //let ok,memberIndex = xmlIndexService.CreateXMLMemberIndex(assemblyName) + //if Com.Succeeded(ok) then + // let ok = memberIndex.BuildMemberIndex() + // if Com.Succeeded(ok) then + // cache.Add(assemblyName, memberIndex) + // Some(memberIndex) + // else None + //else None let AppendMemberData(xmlCollector: ITaggedTextCollector, exnCollector: ITaggedTextCollector, xmlDocReader: XmlDocReader, showExceptions, showParameters) = AppendHardLine xmlCollector @@ -259,9 +259,9 @@ module internal XmlDocumentation = /// ITaggedTextCollector to add to exnCollector: ITaggedTextCollector, /// Name of the library file - filename:string, + _filename:string, /// Signature of the comment - signature:string, + _signature:string, /// Whether to show exceptions showExceptions:bool, /// Whether to show parameters and return @@ -270,14 +270,15 @@ module internal XmlDocumentation = paramName:string option ) = try - match GetMemberIndexOfAssembly(filename) with - | Some(index) -> - let _,idx = index.ParseMemberSignature(signature) - if idx <> 0u then - let ok,xml = index.GetMemberXML(idx) - if Com.Succeeded(ok) then - (this:>IDocumentationBuilder).AppendDocumentationFromProcessedXML(xmlCollector, exnCollector, xml, showExceptions, showParameters, paramName) - | None -> () + //match GetMemberIndexOfAssembly(filename) with + //| Some(index) -> + // let _,idx = index.ParseMemberSignature(signature) + // if idx <> 0u then + // let ok,xml = index.GetMemberXML(idx) + // if Com.Succeeded(ok) then + // (this:>IDocumentationBuilder).AppendDocumentationFromProcessedXML(xmlCollector, exnCollector, xml, showExceptions, showParameters, paramName) + //| None -> () + (this:>IDocumentationBuilder).AppendDocumentationFromProcessedXML(xmlCollector, exnCollector, "Hi", showExceptions, showParameters, paramName) with e-> Assert.Exception(e) reraise() @@ -317,7 +318,7 @@ module internal XmlDocumentation = let ProcessGenericParameters (tps: Layout list) = if not tps.IsEmpty then AppendHardLine typeParameterMapCollector - AppendOnNewLine typeParameterMapCollector (SR.GenericParametersHeader()) + AppendOnNewLine typeParameterMapCollector ("SR.GenericParametersHeader()") for tp in tps do AppendHardLine typeParameterMapCollector typeParameterMapCollector.Add(tagSpace " ") @@ -381,6 +382,7 @@ module internal XmlDocumentation = let BuildMethodParamText(documentationProvider, xmlCollector, xml, paramName) = AppendXmlComment(documentationProvider, TextSanitizingCollector(xmlCollector), TextSanitizingCollector(xmlCollector), xml, false, true, Some paramName) - let documentationBuilderCache = ConditionalWeakTable() - let CreateDocumentationBuilder(xmlIndexService: IVsXMLMemberIndexService) = - documentationBuilderCache.GetValue(xmlIndexService,(fun _ -> Provider(xmlIndexService) :> IDocumentationBuilder)) \ No newline at end of file + //let documentationBuilderCache = ConditionalWeakTable() + let CreateDocumentationBuilder((*xmlIndexService: IVsXMLMemberIndexService*)) = + //documentationBuilderCache.GetValue(xmlIndexService,(fun _ -> Provider((*xmlIndexService*)) :> IDocumentationBuilder)) + Provider((*xmlIndexService*)) :> IDocumentationBuilder \ 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 a598bfde4b7..f3ddfb59df9 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -1,11 +1,9 @@ - - - - + Library $(NoWarn);75 - $(NoWarn);44 + $(NoWarn);44 + true true $(SystemValueTupleVersion) @@ -13,9 +11,28 @@ false net472 - + embedded false + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor + 0 + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor\FSharp.Editor.XML + false + + + false + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor + false + + + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor + 4 + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor\FSharp.Editor.XML + false + + + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor + false @@ -24,13 +41,18 @@ - + - - + + + + + + + @@ -43,11 +65,11 @@ - + - + @@ -56,14 +78,14 @@ - + - + - + - + @@ -85,11 +107,6 @@ $(VSAssemblyVersion) $PackageFolder$\FSharp.Editor.dll - - - - - @@ -97,7 +114,6 @@ - @@ -139,42 +155,52 @@ PublicResXFileCodeGenerator FSharp.Editor.Designer.fs - - - - - - - - - - - - - - + + + + + + + + + + + + - - - - + + - Common\LspExternalAccess.fs - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + - + \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml new file mode 100644 index 00000000000..d5c7f2af191 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs index 62e31e137b4..fc5bef7af5b 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs @@ -12,7 +12,8 @@ open Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.LanguageServices open FSharp.NativeInterop open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics - +open MonoDevelop.Ide +open MonoDevelop.Ide.TypeSystem #nowarn "9" // NativePtr.toNativeInt // Exposes FSharpChecker as MEF export @@ -21,31 +22,32 @@ type internal FSharpCheckerProvider [] ( analyzerService: IFSharpDiagnosticAnalyzerService, - [)>] workspace: VisualStudioWorkspace, + //[)>] workspace: VisualStudioWorkspace, settings: EditorOptions ) = + let workspace = IdeApp.TypeSystemService.Workspace :?> MonoDevelopWorkspace + let tryGetMetadataSnapshot (_path, _timeStamp) = - let tryGetMetadataSnapshot (path, timeStamp) = - try - let md = Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetMetadata(workspace, path, timeStamp) - let amd = (md :?> AssemblyMetadata) - let mmd = amd.GetModules().[0] - let mmr = mmd.GetMetadataReader() + //try + // let md = Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetMetadata(workspace, path, timeStamp) + // let amd = (md :?> AssemblyMetadata) + // let mmd = amd.GetModules().[0] + // let mmr = mmd.GetMetadataReader() - // "lifetime is timed to Metadata you got from the GetMetadata(...). As long as you hold it strongly, raw - // memory we got from metadata reader will be alive. Once you are done, just let everything go and - // let finalizer handle resource rather than calling Dispose from Metadata directly. It is shared metadata. - // You shouldn't dispose it directly." + // // "lifetime is timed to Metadata you got from the GetMetadata(...). As long as you hold it strongly, raw + // // memory we got from metadata reader will be alive. Once you are done, just let everything go and + // // let finalizer handle resource rather than calling Dispose from Metadata directly. It is shared metadata. + // // You shouldn't dispose it directly." - let objToHold = box md + // let objToHold = box md - // We don't expect any ilread WeakByteFile to be created when working in Visual Studio - Debug.Assert((FSharp.Compiler.AbstractIL.ILBinaryReader.GetStatistics().weakByteFileCount = 0), "Expected weakByteFileCount to be zero when using F# in Visual Studio. Was there a problem reading a .NET binary?") + // // We don't expect any ilread WeakByteFile to be created when working in Visual Studio + // Debug.Assert((FSharp.Compiler.AbstractIL.ILBinaryReader.GetStatistics().weakByteFileCount = 0), "Expected weakByteFileCount to be zero when using F# in Visual Studio. Was there a problem reading a .NET binary?") - Some (objToHold, NativePtr.toNativeInt mmr.MetadataPointer, mmr.MetadataLength) - with ex -> - // We catch all and let the backup routines in the F# compiler find the error - Assert.Exception(ex) + // Some (objToHold, NativePtr.toNativeInt mmr.MetadataPointer, mmr.MetadataLength) + //with ex -> + //// We catch all and let the backup routines in the F# compiler find the error + //Assert.Exception(ex) None diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index 5a2c3eed966..7fcb671b444 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -80,7 +80,7 @@ type private FSharpProjectOptionsMessage = | ClearSingleFileOptionsCache of DocumentId [] -type private FSharpProjectOptionsReactor (_workspace: VisualStudioWorkspace, settings: EditorOptions, _serviceProvider, checkerProvider: FSharpCheckerProvider) = +type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) settings: EditorOptions, (*_serviceProvider,*) checkerProvider: FSharpCheckerProvider) = let cancellationTokenSource = new CancellationTokenSource() // Hack to store command line options from HandleCommandLineChanges @@ -133,15 +133,15 @@ type private FSharpProjectOptionsReactor (_workspace: VisualStudioWorkspace, set return Some(parsingOptions, projectOptions) } - let tryGetProjectSite (project: Project) = - // Cps - if cpsCommandLineOptions.ContainsKey project.Id then - Some (mapCpsProjectToSite(project, cpsCommandLineOptions)) - else - // Legacy - match legacyProjectSites.TryGetValue project.Id with - | true, site -> Some site - | _ -> None + //let tryGetProjectSite (project: Project) = + //// Cps + //if cpsCommandLineOptions.ContainsKey project.Id then + // Some (mapCpsProjectToSite(project, cpsCommandLineOptions)) + //else + //// Legacy + //match legacyProjectSites.TryGetValue project.Id with + //| true, site -> Some site + //| _ -> None let rec tryComputeOptions (project: Project) = async { @@ -167,42 +167,48 @@ type private FSharpProjectOptionsReactor (_workspace: VisualStudioWorkspace, set return None else - match tryGetProjectSite project with - | None -> return None - | Some projectSite -> - - let otherOptions = - project.ProjectReferences - |> Seq.map (fun x -> "-r:" + project.Solution.GetProject(x.ProjectId).OutputFilePath) - |> Array.ofSeq - |> Array.append ( - project.MetadataReferences.OfType() - |> Seq.map (fun x -> "-r:" + x.FilePath) - |> Array.ofSeq - |> Array.append ( - // Clear any references from CompilationOptions. - // We get the references from Project.ProjectReferences/Project.MetadataReferences. - projectSite.CompilationOptions - |> Array.filter (fun x -> not (x.Contains("-r:"))) - ) - ) - - let projectOptions = - { - ProjectFileName = projectSite.ProjectFileName - ProjectId = Some(projectId.ToFSharpProjectIdString()) - SourceFiles = projectSite.CompilationSourceFiles - OtherOptions = otherOptions - ReferencedProjects = referencedProjects.ToArray() - IsIncompleteTypeCheckEnvironment = projectSite.IsIncompleteTypeCheckEnvironment - UseScriptResolutionRules = SourceFile.MustBeSingleFileProject (Path.GetFileName(project.FilePath)) - LoadTime = projectSite.LoadTime - UnresolvedReferences = None - OriginalLoadReferences = [] - ExtraProjectInfo= None - Stamp = Some(int64 (project.Version.GetHashCode())) - } - + //match tryGetProjectSite project with + //| None -> return None + //| Some projectSite -> + + MonoDevelop.FSharp.MDLanguageService.DisableVirtualFileSystem() + let projectOpts = MonoDevelop.FSharp.MDLanguageService.Instance.GetProjectCheckerOptions(project.FilePath) + //let otherOptions = + // project.ProjectReferences + // |> Seq.map (fun x -> "-r:" + project.Solution.GetProject(x.ProjectId).OutputFilePath) + // |> Array.ofSeq + // |> Array.append ( + // project.MetadataReferences.OfType() + // |> Seq.map (fun x -> "-r:" + x.FilePath) + // |> Array.ofSeq + // |> Array.append ( + // // Clear any references from CompilationOptions. + // // We get the references from Project.ProjectReferences/Project.MetadataReferences. + // projectSite.CompilationOptions + // |> Array.filter (fun x -> not (x.Contains("-r:"))) + // ) + // ) + + //let projectOptions = + //{ + // ProjectFileName = projectSite.ProjectFileName + // ProjectId = Some(projectId.ToFSharpProjectIdString()) + // SourceFiles = projectSite.CompilationSourceFiles + // OtherOptions = otherOptions + // ReferencedProjects = referencedProjects.ToArray() + // IsIncompleteTypeCheckEnvironment = projectSite.IsIncompleteTypeCheckEnvironment + // UseScriptResolutionRules = SourceFile.MustBeSingleFileProject (Path.GetFileName(project.FilePath)) + // LoadTime = projectSite.LoadTime + // UnresolvedReferences = None + // OriginalLoadReferences = [] + // ExtraProjectInfo= None + // Stamp = Some(int64 (project.Version.GetHashCode())) + //} + + + let projectOptions = projectOpts.Value + let sourceFiles = projectOptions.OtherOptions.Where(fun o -> o.StartsWith("/")) + let projectOptions = { projectOptions with SourceFiles = sourceFiles.ToArray() } // This can happen if we didn't receive the callback from HandleCommandLineChanges yet. if Array.isEmpty projectOptions.SourceFiles then return None @@ -307,24 +313,24 @@ type internal FSharpProjectOptionsManager [] ( checkerProvider: FSharpCheckerProvider, - [)>] workspace: VisualStudioWorkspace, - [)>] serviceProvider: System.IServiceProvider, + //[)>] workspace: VisualStudioWorkspace, + //[)>] serviceProvider: System.IServiceProvider, settings: EditorOptions ) = - let projectDisplayNameOf projectFileName = - if String.IsNullOrWhiteSpace projectFileName then projectFileName - else Path.GetFileNameWithoutExtension projectFileName + //let projectDisplayNameOf projectFileName = + //if String.IsNullOrWhiteSpace projectFileName then projectFileName + //else Path.GetFileNameWithoutExtension projectFileName - let reactor = new FSharpProjectOptionsReactor(workspace, settings, serviceProvider, checkerProvider) + let reactor = new FSharpProjectOptionsReactor(settings, (*serviceProvider,*) checkerProvider) - do - // We need to listen to this event for lifecycle purposes. - workspace.WorkspaceChanged.Add(fun args -> - match args.Kind with - | WorkspaceChangeKind.ProjectRemoved -> reactor.ClearOptionsByProjectId(args.ProjectId) - | _ -> () - ) + //do + //// We need to listen to this event for lifecycle purposes. + //workspace.WorkspaceChanged.Add(fun args -> + // match args.Kind with + // | WorkspaceChangeKind.ProjectRemoved -> reactor.ClearOptionsByProjectId(args.ProjectId) + // | _ -> () + //) member __.SetLegacyProjectSite (projectId, projectSite) = reactor.SetLegacyProjectSite (projectId, projectSite) @@ -367,27 +373,27 @@ type internal FSharpProjectOptionsManager return result |> Option.map(fun (parsingOptions, _, projectOptions) -> parsingOptions, projectOptions) } - [] - /// This handles commandline change notifications from the Dotnet Project-system - /// Prior to VS 15.7 path contained path to project file, post 15.7 contains target binpath - /// binpath is more accurate because a project file can have multiple in memory projects based on configuration - member __.HandleCommandLineChanges(path:string, sources:ImmutableArray, _references:ImmutableArray, options:ImmutableArray) = - use _logBlock = Logger.LogBlock(LogEditorFunctionId.LanguageService_HandleCommandLineArgs) + //[] + ///// This handles commandline change notifications from the Dotnet Project-system + ///// Prior to VS 15.7 path contained path to project file, post 15.7 contains target binpath + ///// binpath is more accurate because a project file can have multiple in memory projects based on configuration + //member __.HandleCommandLineChanges(path:string, sources:ImmutableArray, _references:ImmutableArray, options:ImmutableArray) = + //use _logBlock = Logger.LogBlock(LogEditorFunctionId.LanguageService_HandleCommandLineArgs) - let projectId = - match Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.TryGetProjectIdByBinPath(workspace, path) with - | true, projectId -> projectId - | false, _ -> Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetOrCreateProjectIdForPath(workspace, path, projectDisplayNameOf path) - let path = Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetProjectFilePath(workspace, projectId) + //let projectId = + // match Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.TryGetProjectIdByBinPath(workspace, path) with + // | true, projectId -> projectId + // | false, _ -> Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetOrCreateProjectIdForPath(workspace, path, projectDisplayNameOf path) + //let path = Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetProjectFilePath(workspace, projectId) - let getFullPath p = - let p' = - if Path.IsPathRooted(p) || path = null then p - else Path.Combine(Path.GetDirectoryName(path), p) - Path.GetFullPathSafe(p') + //let getFullPath p = + // let p' = + // if Path.IsPathRooted(p) || path = null then p + // else Path.Combine(Path.GetDirectoryName(path), p) + // Path.GetFullPathSafe(p') - let sourcePaths = sources |> Seq.map(fun s -> getFullPath s.Path) |> Seq.toArray + //let sourcePaths = sources |> Seq.map(fun s -> getFullPath s.Path) |> Seq.toArray - reactor.SetCpsCommandLineOptions(projectId, sourcePaths, options.ToArray()) + //reactor.SetCpsCommandLineOptions(projectId, sourcePaths, options.ToArray()) member __.Checker = checkerProvider.Checker diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index db2ccf139dd..6ecba291ba7 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -57,32 +57,32 @@ type internal FSharpCheckerWorkspaceServiceFactory member __.Checker = checkerProvider.Checker member __.FSharpProjectOptionsManager = projectInfoManager } -[] -type private FSharpSolutionEvents(projectManager: FSharpProjectOptionsManager) = +//[] +//type private FSharpSolutionEvents(projectManager: FSharpProjectOptionsManager) = - interface IVsSolutionEvents with +// interface IVsSolutionEvents with - member __.OnAfterCloseSolution(_) = - projectManager.Checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() - VSConstants.S_OK +// member __.OnAfterCloseSolution(_) = +// projectManager.Checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() +// VSConstants.S_OK - member __.OnAfterLoadProject(_, _) = VSConstants.E_NOTIMPL +// member __.OnAfterLoadProject(_, _) = VSConstants.E_NOTIMPL - member __.OnAfterOpenProject(_, _) = VSConstants.E_NOTIMPL +// member __.OnAfterOpenProject(_, _) = VSConstants.E_NOTIMPL - member __.OnAfterOpenSolution(_, _) = VSConstants.E_NOTIMPL +// member __.OnAfterOpenSolution(_, _) = VSConstants.E_NOTIMPL - member __.OnBeforeCloseProject(_, _) = VSConstants.E_NOTIMPL +// member __.OnBeforeCloseProject(_, _) = VSConstants.E_NOTIMPL - member __.OnBeforeCloseSolution(_) = VSConstants.E_NOTIMPL +// member __.OnBeforeCloseSolution(_) = VSConstants.E_NOTIMPL - member __.OnBeforeUnloadProject(_, _) = VSConstants.E_NOTIMPL +// member __.OnBeforeUnloadProject(_, _) = VSConstants.E_NOTIMPL - member __.OnQueryCloseProject(_, _, _) = VSConstants.E_NOTIMPL +// member __.OnQueryCloseProject(_, _, _) = VSConstants.E_NOTIMPL - member __.OnQueryCloseSolution(_, _) = VSConstants.E_NOTIMPL +// member __.OnQueryCloseSolution(_, _) = VSConstants.E_NOTIMPL - member __.OnQueryUnloadProject(_, _) = VSConstants.E_NOTIMPL +// member __.OnQueryUnloadProject(_, _) = VSConstants.E_NOTIMPL [, Microsoft.CodeAnalysis.Host.Mef.ServiceLayer.Default)>] type internal FSharpSettingsFactory @@ -90,158 +90,158 @@ type internal FSharpSettingsFactory interface Microsoft.CodeAnalysis.Host.Mef.IWorkspaceServiceFactory with member __.CreateService(_) = upcast settings -[] -//[, -// "F# Tools", "F# Interactive", // category/sub-category on Tools>Options... -// 6000s, 6001s, // resource id for localisation of the above -// true)>] // true = supports automation -//[] // <-- resource ID for localised name -//[, -// // The following should place the ToolWindow with the OutputWindow by default. -// Orientation=ToolWindowOrientation.Bottom, -// Style=VsDockStyle.Tabbed, -// PositionX = 0, -// PositionY = 0, -// Width = 360, -// Height = 120, -// Window="34E76E81-EE4A-11D0-AE2E-00A0C90FFFC3")>] -//[, "F#", null, "IntelliSense", "6008")>] -//[, "F#", null, "QuickInfo", "6009")>] -//[, "F#", null, "Code Fixes", "6010")>] -//[, "F#", null, "Performance", "6011")>] -//[, "F#", null, "Advanced", "6012")>] -//[, "F#", null, "CodeLens", "6013")>] -//[, "F#", null, "Formatting", "6014")>] -//[] -//// 64 represents a hex number. It needs to be greater than 37 so the TextMate editor will not be chosen as higher priority. -//[, ".fs", 64)>] -//[, ".fsi", 64)>] -//[, ".fsscript", 64)>] -//[, ".fsx", 64)>] -//[, ".ml", 64)>] -//[, ".mli", 64)>] -//[, 101s, CommonPhysicalViewAttributes = Constants.FSharpEditorFactoryPhysicalViewAttributes)>] -[, ".fs")>] -[, ".fsi")>] -[, ".fsx")>] -[, ".fsscript")>] -[, ".ml")>] -[, ".mli")>] -[] -[, - strLanguageName = FSharpConstants.FSharpLanguageName, - languageResourceID = 100, - MatchBraces = true, - MatchBracesAtCaret = true, - ShowCompletion = true, - ShowMatchingBrace = true, - ShowSmartIndent = true, - EnableAsyncCompletion = true, - QuickInfo = true, - DefaultToInsertSpaces = true, - CodeSense = true, - DefaultToNonHotURLs = true, - RequestStockColors = true, - EnableCommenting = true, - CodeSenseDelay = 100, - ShowDropDownOptions = true)>] -type internal FSharpPackage() as this = - inherit AbstractPackage() - - //let mutable vfsiToolWindow = Unchecked.defaultof - //let GetToolWindowAsITestVFSI() = - //if vfsiToolWindow = Unchecked.defaultof<_> then - // vfsiToolWindow <- this.FindToolWindow(typeof, 0, true) :?> Microsoft.VisualStudio.FSharp.Interactive.FsiToolWindow - //vfsiToolWindow :> Microsoft.VisualStudio.FSharp.Interactive.ITestVFSI - - let mutable solutionEventsOpt = None - - // FSI-LINKAGE-POINT: unsited init - //do - //Microsoft.VisualStudio.FSharp.Interactive.Hooks.fsiConsoleWindowPackageCtorUnsited (this :> Package) - - override this.InitializeAsync(cancellationToken: CancellationToken, progress: IProgress) : Tasks.Task = - // `base.` methods can't be called in the `async` builder, so we have to cache it - let baseInitializeAsync = base.InitializeAsync(cancellationToken, progress) - let task = - async { - do! baseInitializeAsync |> Async.AwaitTask - - //let! commandService = this.GetServiceAsync(typeof) |> Async.AwaitTask // FSI-LINKAGE-POINT - //let commandService = commandService :?> OleMenuCommandService - let packageInit () = - // FSI-LINKAGE-POINT: sited init - //Microsoft.VisualStudio.FSharp.Interactive.Hooks.fsiConsoleWindowPackageInitalizeSited (this :> Package) commandService - - // FSI-LINKAGE-POINT: private method GetDialogPage forces fsi options to be loaded - //let _fsiPropertyPage = this.GetDialogPage(typeof) - let projectInfoManager = this.ComponentModel.DefaultExportProvider.GetExport().Value - let solution = this.GetServiceAsync(typeof).Result - let solution = solution :?> IVsSolution - let solutionEvents = FSharpSolutionEvents(projectInfoManager) - let rdt = this.GetServiceAsync(typeof).Result - let rdt = rdt :?> IVsRunningDocumentTable - - solutionEventsOpt <- Some(solutionEvents) - solution.AdviseSolutionEvents(solutionEvents) |> ignore - - let projectContextFactory = this.ComponentModel.GetService() - let workspace = this.ComponentModel.GetService() - let miscFilesWorkspace = this.ComponentModel.GetService() - let _singleFileWorkspaceMap = new SingleFileWorkspaceMap(workspace, miscFilesWorkspace, projectInfoManager, projectContextFactory, rdt) - let _legacyProjectWorkspaceMap = new LegacyProjectWorkspaceMap(solution, projectInfoManager, projectContextFactory) - () - let awaiter = this.JoinableTaskFactory.SwitchToMainThreadAsync().GetAwaiter() - if awaiter.IsCompleted then - packageInit() // already on the UI thread - else - awaiter.OnCompleted(fun () -> packageInit()) - - } |> Async.StartAsTask - upcast task // convert Task to Task - - override this.RoslynLanguageName = FSharpConstants.FSharpLanguageName - override this.CreateWorkspace() = this.ComponentModel.GetService() - override this.CreateLanguageService() = FSharpLanguageService(this) - override this.CreateEditorFactories() = this.CreateEditorFactories()// seq { yield FSharpEditorFactory(this) :> IVsEditorFactory } - override this.RegisterMiscellaneousFilesWorkspaceInformation(miscFilesWorkspace) = - miscFilesWorkspace.RegisterLanguage(Guid(FSharpConstants.languageServiceGuidString), FSharpConstants.FSharpLanguageName, ".fsx") - - //interface Microsoft.VisualStudio.FSharp.Interactive.ITestVFSI with - //member this.SendTextInteraction(s:string) = - // GetToolWindowAsITestVFSI().SendTextInteraction(s) - //member this.GetMostRecentLines(n:int) : string[] = - //GetToolWindowAsITestVFSI().GetMostRecentLines(n) - -[] -type internal FSharpLanguageService(package : FSharpPackage) = - inherit AbstractLanguageService(package) - - override this.Initialize() = - base.Initialize() - - this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Completion.FSharpCompletionOptions.BlockForCompletionItems, FSharpConstants.FSharpLanguageName, false) - this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Shared.Options.FSharpServiceFeatureOnOffOptions.ClosedFileDiagnostic, FSharpConstants.FSharpLanguageName, Nullable false) - - let theme = package.ComponentModel.DefaultExportProvider.GetExport().Value - theme.SetColors() - - override __.ContentTypeName = FSharpConstants.FSharpContentTypeName - override __.LanguageName = FSharpConstants.FSharpLanguageName - override __.RoslynLanguageName = FSharpConstants.FSharpLanguageName - - override __.LanguageServiceId = new Guid(FSharpConstants.languageServiceGuidString) - override __.DebuggerLanguageId = DebuggerEnvironment.GetLanguageID() - - override __.CreateContext(_,_,_,_,_) = raise(System.NotImplementedException()) - - override this.SetupNewTextView(textView) = - base.SetupNewTextView(textView) - - // Toggles outlining (or code folding) based on settings - let outliningManagerService = this.Package.ComponentModel.GetService() - let wpfTextView = this.EditorAdaptersFactoryService.GetWpfTextView(textView) - let outliningManager = outliningManagerService.GetOutliningManager(wpfTextView) - if not (isNull outliningManager) then - let settings = this.Workspace.Services.GetService() - outliningManager.Enabled <- settings.Advanced.IsOutliningEnabled +//[] +////[, +//// "F# Tools", "F# Interactive", // category/sub-category on Tools>Options... +//// 6000s, 6001s, // resource id for localisation of the above +//// true)>] // true = supports automation +////[] // <-- resource ID for localised name +////[, +//// // The following should place the ToolWindow with the OutputWindow by default. +//// Orientation=ToolWindowOrientation.Bottom, +//// Style=VsDockStyle.Tabbed, +//// PositionX = 0, +//// PositionY = 0, +//// Width = 360, +//// Height = 120, +//// Window="34E76E81-EE4A-11D0-AE2E-00A0C90FFFC3")>] +////[, "F#", null, "IntelliSense", "6008")>] +////[, "F#", null, "QuickInfo", "6009")>] +////[, "F#", null, "Code Fixes", "6010")>] +////[, "F#", null, "Performance", "6011")>] +////[, "F#", null, "Advanced", "6012")>] +////[, "F#", null, "CodeLens", "6013")>] +////[, "F#", null, "Formatting", "6014")>] +////[] +////// 64 represents a hex number. It needs to be greater than 37 so the TextMate editor will not be chosen as higher priority. +////[, ".fs", 64)>] +////[, ".fsi", 64)>] +////[, ".fsscript", 64)>] +////[, ".fsx", 64)>] +////[, ".ml", 64)>] +////[, ".mli", 64)>] +////[, 101s, CommonPhysicalViewAttributes = Constants.FSharpEditorFactoryPhysicalViewAttributes)>] +//[, ".fs")>] +//[, ".fsi")>] +//[, ".fsx")>] +//[, ".fsscript")>] +//[, ".ml")>] +//[, ".mli")>] +//[] +//[, +// strLanguageName = FSharpConstants.FSharpLanguageName, +// languageResourceID = 100, +// MatchBraces = true, +// MatchBracesAtCaret = true, +// ShowCompletion = true, +// ShowMatchingBrace = true, +// ShowSmartIndent = true, +// EnableAsyncCompletion = true, +// QuickInfo = true, +// DefaultToInsertSpaces = true, +// CodeSense = true, +// DefaultToNonHotURLs = true, +// RequestStockColors = true, +// EnableCommenting = true, +// CodeSenseDelay = 100, +// ShowDropDownOptions = true)>] +//type internal FSharpPackage() as this = +// inherit AbstractPackage() + +// //let mutable vfsiToolWindow = Unchecked.defaultof +// //let GetToolWindowAsITestVFSI() = +// //if vfsiToolWindow = Unchecked.defaultof<_> then +// // vfsiToolWindow <- this.FindToolWindow(typeof, 0, true) :?> Microsoft.VisualStudio.FSharp.Interactive.FsiToolWindow +// //vfsiToolWindow :> Microsoft.VisualStudio.FSharp.Interactive.ITestVFSI + +// let mutable solutionEventsOpt = None + +// // FSI-LINKAGE-POINT: unsited init +// //do +// //Microsoft.VisualStudio.FSharp.Interactive.Hooks.fsiConsoleWindowPackageCtorUnsited (this :> Package) + +// override this.InitializeAsync(cancellationToken: CancellationToken, progress: IProgress) : Tasks.Task = +// // `base.` methods can't be called in the `async` builder, so we have to cache it +// let baseInitializeAsync = base.InitializeAsync(cancellationToken, progress) +// let task = +// async { +// do! baseInitializeAsync |> Async.AwaitTask + +// //let! commandService = this.GetServiceAsync(typeof) |> Async.AwaitTask // FSI-LINKAGE-POINT +// //let commandService = commandService :?> OleMenuCommandService +// let packageInit () = +// // FSI-LINKAGE-POINT: sited init +// //Microsoft.VisualStudio.FSharp.Interactive.Hooks.fsiConsoleWindowPackageInitalizeSited (this :> Package) commandService + +// // FSI-LINKAGE-POINT: private method GetDialogPage forces fsi options to be loaded +// //let _fsiPropertyPage = this.GetDialogPage(typeof) +// let projectInfoManager = this.ComponentModel.DefaultExportProvider.GetExport().Value +// let solution = this.GetServiceAsync(typeof).Result +// let solution = solution :?> IVsSolution +// let solutionEvents = FSharpSolutionEvents(projectInfoManager) +// let rdt = this.GetServiceAsync(typeof).Result +// let rdt = rdt :?> IVsRunningDocumentTable + +// solutionEventsOpt <- Some(solutionEvents) +// solution.AdviseSolutionEvents(solutionEvents) |> ignore + +// let projectContextFactory = this.ComponentModel.GetService() +// let workspace = this.ComponentModel.GetService() +// let miscFilesWorkspace = this.ComponentModel.GetService() +// let _singleFileWorkspaceMap = new SingleFileWorkspaceMap(workspace, miscFilesWorkspace, projectInfoManager, projectContextFactory, rdt) +// let _legacyProjectWorkspaceMap = new LegacyProjectWorkspaceMap(solution, projectInfoManager, projectContextFactory) +// () +// let awaiter = this.JoinableTaskFactory.SwitchToMainThreadAsync().GetAwaiter() +// if awaiter.IsCompleted then +// packageInit() // already on the UI thread +// else +// awaiter.OnCompleted(fun () -> packageInit()) + +// } |> Async.StartAsTask +// upcast task // convert Task to Task + +// override this.RoslynLanguageName = FSharpConstants.FSharpLanguageName +// override this.CreateWorkspace() = this.ComponentModel.GetService() +// override this.CreateLanguageService() = FSharpLanguageService(this) +// override this.CreateEditorFactories() = this.CreateEditorFactories()// seq { yield FSharpEditorFactory(this) :> IVsEditorFactory } +// override this.RegisterMiscellaneousFilesWorkspaceInformation(miscFilesWorkspace) = +// miscFilesWorkspace.RegisterLanguage(Guid(FSharpConstants.languageServiceGuidString), FSharpConstants.FSharpLanguageName, ".fsx") + +// //interface Microsoft.VisualStudio.FSharp.Interactive.ITestVFSI with +// //member this.SendTextInteraction(s:string) = +// // GetToolWindowAsITestVFSI().SendTextInteraction(s) +// //member this.GetMostRecentLines(n:int) : string[] = +// //GetToolWindowAsITestVFSI().GetMostRecentLines(n) + +//[] +//type internal FSharpLanguageService(package : FSharpPackage) = + ////inherit AbstractLanguageService(package) + + //member this.Initialize() = + // base.Initialize() + + // this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Completion.FSharpCompletionOptions.BlockForCompletionItems, FSharpConstants.FSharpLanguageName, false) + // this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Shared.Options.FSharpServiceFeatureOnOffOptions.ClosedFileDiagnostic, FSharpConstants.FSharpLanguageName, Nullable false) + + // let theme = package.ComponentModel.DefaultExportProvider.GetExport().Value + // theme.SetColors() + + //member __.ContentTypeName = FSharpConstants.FSharpContentTypeName + //member __.LanguageName = FSharpConstants.FSharpLanguageName + //member __.RoslynLanguageName = FSharpConstants.FSharpLanguageName + + //member __.LanguageServiceId = new Guid(FSharpConstants.languageServiceGuidString) + //member __.DebuggerLanguageId = DebuggerEnvironment.GetLanguageID() + + ////member __.CreateContext(_,_,_,_,_) = raise(System.NotImplementedException()) + + //member this.SetupNewTextView(textView) = + //base.SetupNewTextView(textView) + + //// Toggles outlining (or code folding) based on settings + //let outliningManagerService = this.Package.ComponentModel.GetService() + //let wpfTextView = this.EditorAdaptersFactoryService.GetWpfTextView(textView) + //let outliningManager = outliningManagerService.GetOutliningManager(wpfTextView) + //if not (isNull outliningManager) then + //let settings = this.Workspace.Services.GetService() + //outliningManager.Enabled <- settings.Advanced.IsOutliningEnabled diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs index a607442e462..7891cd8a0ed 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs @@ -107,13 +107,13 @@ module private ExternalSymbol = | _ -> [] // TODO: Uncomment code when VS has a fix for updating the status bar. -type internal StatusBar(statusBar: IVsStatusbar) = +type internal StatusBar((*statusBar: IVsStatusbar*)) = let mutable _searchIcon = int16 Microsoft.VisualStudio.Shell.Interop.Constants.SBAI_Find :> obj - let _clear() = + let _clear() = () // unfreeze the statusbar - statusBar.FreezeOutput 0 |> ignore - statusBar.Clear() |> ignore + //statusBar.FreezeOutput 0 |> ignore + //statusBar.Clear() |> ignore member __.Message(_msg: string) = () diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs index 1a5b1e611ec..003f338e179 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs @@ -25,7 +25,7 @@ type internal FSharpGoToDefinitionService ) = let gtd = GoToDefinition(checkerProvider.Checker, projectInfoManager) - let statusBar = StatusBar(ServiceProvider.GlobalProvider.GetService()) + let statusBar = StatusBar((*ServiceProvider.GlobalProvider.GetService()*)) interface IFSharpGoToDefinitionService with /// Invoked with Peek Definition. diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs index 0d969d9ca14..d22e54a661c 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs @@ -28,11 +28,11 @@ type internal FSharpNavigableSymbol(item: FSharpNavigableItem, span: SnapshotSpa member __.SymbolSpan = span -type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, serviceProvider: IServiceProvider) = +type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager(*, serviceProvider: IServiceProvider*)) = let mutable disposed = false let gtd = GoToDefinition(checkerProvider.Checker, projectInfoManager) - let statusBar = StatusBar(serviceProvider.GetService()) + let statusBar = StatusBar((*serviceProvider.GetService()*)) interface INavigableSymbolSource with member __.GetNavigableSymbolAsync(triggerSpan: SnapshotSpan, cancellationToken: CancellationToken) = @@ -89,11 +89,11 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider type internal FSharpNavigableSymbolService [] ( - [)>] serviceProvider: IServiceProvider, + //[)>] serviceProvider: IServiceProvider, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager ) = interface INavigableSymbolSourceProvider with member __.TryCreateNavigableSymbolSource(_: ITextView, _: ITextBuffer) = - new FSharpNavigableSymbolSource(checkerProvider, projectInfoManager, serviceProvider) :> INavigableSymbolSource \ No newline at end of file + new FSharpNavigableSymbolSource(checkerProvider, projectInfoManager(*, serviceProvider*)) :> INavigableSymbolSource \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs b/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs index f1cc8a6d751..f7a697342fc 100644 --- a/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs +++ b/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs @@ -135,6 +135,7 @@ type EditorOptions [] module internal WorkspaceSettingFromDocumentExtension = + let options = EditorOptions() type Microsoft.CodeAnalysis.Document with - member this.FSharpOptions = - this.Project.Solution.Workspace.Services.GetService() : EditorOptions + member this.FSharpOptions = options + //this.Project.Solution.Workspace.Services.GetService() : EditorOptions diff --git a/vsintegration/src/FSharp.Editor/Options/SettingsPersistence.fs b/vsintegration/src/FSharp.Editor/Options/SettingsPersistence.fs index febc6764f9b..38e5e3724a9 100644 --- a/vsintegration/src/FSharp.Editor/Options/SettingsPersistence.fs +++ b/vsintegration/src/FSharp.Editor/Options/SettingsPersistence.fs @@ -20,11 +20,11 @@ type SettingsStore((*serviceProvider: IServiceProvider*)) = //let settingsManager = serviceProvider.GetService(typeof) :?> ISettingsManager //let storageKeyVersions (typ: Type) = - //// "TextEditor" prefix seems to be required for settings changes to be synced between IDE instances - //[ "TextEditor.FSharp." + typ.Namespace + "." + typ.Name - //// we keep this old storage key to upgrade without reverting user changes - //typ.Namespace + "." + typ.Name ] - + // // "TextEditor" prefix seems to be required for settings changes to be synced between IDE instances + // [ "TextEditor.FSharp." + typ.Namespace + "." + typ.Name + // // we keep this old storage key to upgrade without reverting user changes + // typ.Namespace + "." + typ.Name ] + //let storageKey (typ: Type) = storageKeyVersions typ |> List.head // Each group of settings is a value of some named type, for example 'IntelliSenseOptions', 'QuickInfoOptions' @@ -39,7 +39,7 @@ type SettingsStore((*serviceProvider: IServiceProvider*)) = | true, (:? 't as value) -> value | _ -> failwithf "Settings %s are not registered." typeof<'t>.Name - //let keepInCache settings = cache.[settings.GetType()] <- settings + let keepInCache settings = cache.[settings.GetType()] <- settings // The settings record, even though immutable, is being effectively mutated in two instances: // when it is passed to the UI (provided it is marked with CLIMutable attribute); @@ -75,8 +75,9 @@ type SettingsStore((*serviceProvider: IServiceProvider*)) = () // This is the point we retrieve the initial value and subscribe to watch for changes - member __.Register (_defaultSettings : 'options) = + member __.Register (defaultSettings : 'options) = //defaultSettings |> updateFromStore |> keepInCache + defaultSettings |> keepInCache //let subset = defaultSettings.GetType() |> storageKey |> settingsManager.GetSubset //// this event is also raised when a setting change occurs in another VS instance, so we can keep everything in sync //PropertyChangedAsyncEventHandler ( fun _ _ -> diff --git a/vsintegration/src/FSharp.Editor/Project/CompilerArguments.fs b/vsintegration/src/FSharp.Editor/Project/CompilerArguments.fs new file mode 100644 index 00000000000..94ba6163c19 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Project/CompilerArguments.fs @@ -0,0 +1,367 @@ +// -------------------------------------------------------------------------------------- +// Common utilities for environment, debugging and working with project files +// -------------------------------------------------------------------------------------- + +namespace MonoDevelop.FSharp + +open System +open System.IO +open System.Reflection +open System.Globalization +open System.Runtime.Versioning +open MonoDevelop.Projects +open MonoDevelop.Ide +open MonoDevelop.Core.Assemblies +open MonoDevelop.Core +open ExtCore +open ExtCore.Control +open FSharp.Compiler.SourceCodeServices + +// -------------------------------------------------------------------------------------- +// Common utilities for working with files & extracting information from +// MonoDevelop objects (e.g. references, project items etc.) +// -------------------------------------------------------------------------------------- + +module CompilerArguments = + + /// Wraps the given string between double quotes + let wrapFile (s:string) = if s.StartsWith "\"" then s else "\"" + s + "\"" + + // Translate the target framework to an enum used by FSharp.CompilerBinding + let getTargetFramework (targetFramework:TargetFrameworkMoniker) = + if targetFramework = TargetFrameworkMoniker.NET_3_5 then FSharpTargetFramework.NET_3_5 + elif targetFramework = TargetFrameworkMoniker.NET_3_0 then FSharpTargetFramework.NET_3_0 + elif targetFramework = TargetFrameworkMoniker.NET_2_0 then FSharpTargetFramework.NET_2_0 + elif targetFramework = TargetFrameworkMoniker.NET_4_0 then FSharpTargetFramework.NET_4_0 + elif targetFramework = TargetFrameworkMoniker.NET_4_5 then FSharpTargetFramework.NET_4_5 + elif targetFramework = TargetFrameworkMoniker.NET_4_6 then FSharpTargetFramework.NET_4_6 + elif targetFramework = TargetFrameworkMoniker.NET_4_6_1 then FSharpTargetFramework.NET_4_6_1 + elif targetFramework = TargetFrameworkMoniker.NET_4_6_2 then FSharpTargetFramework.NET_4_6_2 + else FSharpTargetFramework.NET_4_6_2 + + module Project = + ///Use the IdeApp.Workspace active configuration failing back to proj.DefaultConfiguration then ConfigurationSelector.Default + let getCurrentConfigurationOrDefault (proj:Project) = + match IdeApp.Workspace with + | ws when ws <> null && ws.ActiveConfiguration <> null -> ws.ActiveConfiguration + | _ -> if proj <> null then proj.DefaultConfiguration.Selector + else ConfigurationSelector.Default + + let isPortable (project: DotNetProject) = + not (String.IsNullOrEmpty project.TargetFramework.Id.Profile) + + let isDotNetCoreProject (project:DotNetProject) = + let properties = project.MSBuildProject.EvaluatedProperties + properties.HasProperty ("TargetFramework") || properties.HasProperty ("TargetFrameworks") + + let getDefaultTargetFramework (runtime:TargetRuntime) = + let newest_net_framework_folder (best:TargetFramework,best_version:int[]) (candidate_framework:TargetFramework) = + if runtime.IsInstalled(candidate_framework) && candidate_framework.Id.Identifier = TargetFrameworkMoniker.ID_NET_FRAMEWORK then + let version = candidate_framework.Id.Version + let parsed_version_s = (if version.[0] = 'v' then version.[1..] else version).Split('.') + let parsed_version = + try + Array.map int parsed_version_s + with + | _ -> [| 0 |] + let mutable level = 0 + let mutable cont = true + let min_level = min parsed_version.Length best_version.Length + let mutable new_best = false + while cont && level < min_level do + if parsed_version.[level] > best_version.[level] then + new_best <- true + cont <- false + elif best_version.[level] > parsed_version.[level] then + cont <- false + else + cont <- true + level <- level + 1 + if new_best then + (candidate_framework, parsed_version) + else + (best,best_version) + else + (best,best_version) + let candidate_frameworks = MonoDevelop.Core.Runtime.SystemAssemblyService.GetTargetFrameworks() + let first = Seq.head candidate_frameworks + let best_info = Seq.fold newest_net_framework_folder (first,[| 0 |]) candidate_frameworks + fst best_info + + module ReferenceResolution = + + let tryGetDefaultReference langVersion targetFramework filename (extrapath: string option) = + let dirs = + match extrapath with + | Some path -> path :: FSharpEnvironment.getDefaultDirectories(langVersion, targetFramework) + | None -> FSharpEnvironment.getDefaultDirectories(langVersion, targetFramework) + FSharpEnvironment.resolveAssembly dirs filename + + let resolutionFailedMessage (n:string) = String.Format ("Resolution: Assembly resolution failed when trying to find default reference for: {0}", n) + /// Generates references for the current project & configuration as a + /// list of strings of the form [ "-r:"; ... ] + let generateReferences (project: DotNetProject, projectAssemblyReferences: AssemblyReference seq, langVersion, targetFramework, shouldWrap) = + [ + let wrapf = if shouldWrap then wrapFile else id + + let getAbsolutePath (ref:AssemblyReference) = + let assemblyPath = ref.FilePath + if assemblyPath.IsAbsolute then + assemblyPath.FullPath |> string + else + let s = Path.Combine(project.FileName.ParentDirectory.ToString(), assemblyPath.ToString()) + Path.GetFullPath s + + let projectReferences = + projectAssemblyReferences + |> Seq.map getAbsolutePath + |> Seq.distinct + + let find assemblyName= + projectReferences + |> Seq.tryFind (fun fn -> fn.EndsWith(assemblyName + ".dll", true, CultureInfo.InvariantCulture) + || fn.EndsWith(assemblyName, true, CultureInfo.InvariantCulture)) + + + // If 'mscorlib.dll' or 'FSharp.Core.dll' is not in the set of references, we try to resolve and add them. + match find "FSharp.Core", find "mscorlib", Project.isDotNetCoreProject project with + | None, Some mscorlib, false -> + // if mscorlib is found without FSharp.Core yield fsharp.core in the same base dir as mscorlib + // falling back to one of the default directories + let extraPath = Some (Path.GetDirectoryName (mscorlib)) + match ReferenceResolution.tryGetDefaultReference langVersion targetFramework "FSharp.Core" extraPath with + | Some ref -> yield "-r:" + wrapf(ref) + | None -> LoggingService.LogWarning(resolutionFailedMessage "FSharp.Core") + | None, None, false -> + // If neither are found yield the default fsharp.core + match ReferenceResolution.tryGetDefaultReference langVersion targetFramework "FSharp.Core" None with + | Some ref -> yield "-r:" + wrapf(ref) + | None -> LoggingService.LogWarning(resolutionFailedMessage "FSharp.Core") + | _ -> () // found them both, no action needed + + for file in projectReferences do + yield "-r:" + wrapf(file) ] + + let generateDebug (config:FSharpCompilerParameters) = + match config.ParentConfiguration.DebugSymbols, config.ParentConfiguration.DebugType with + | true, typ -> + match typ with + | "full" -> "--debug:full" + | "pdbonly" -> "--debug:pdbonly" + | _ -> "--debug+" + | false, _ -> "--debug-" + + let getSharedAssetFilesFromReferences (project:DotNetProject) = + project.References + |> Seq.filter (fun r -> r.ExtendedProperties.Contains("MSBuild.SharedAssetsProject")) + |> Seq.collect (fun r -> (r.ResolveProject project.ParentSolution).Files) + |> Seq.map (fun f -> f.FilePath) + |> Set.ofSeq + + let getCompiledFiles project = + let sharedAssetFiles = getSharedAssetFilesFromReferences project + + project.Files + // Shared Asset files need to be referenced first + |> Seq.sortByDescending (fun f -> sharedAssetFiles.Contains f.FilePath) + |> Seq.filter(fun f -> f.FilePath.Extension = ".fs") + |> Seq.map(fun f -> f.Name) + |> Seq.distinct + + /// Generates command line options for the compiler specified by the + /// F# compiler options (debugging, tail-calls etc.), custom command line + /// parameters and assemblies referenced by the project ("-r" options) + let generateCompilerOptions (project:DotNetProject, projectAssemblyReferences: AssemblyReference seq, fsconfig:FSharpCompilerParameters, reqLangVersion, targetFramework, configSelector, shouldWrap) = + let dashr = generateReferences (project, projectAssemblyReferences, reqLangVersion, targetFramework, shouldWrap) |> Array.ofSeq + + let splitByChars (chars: char array) (s:string) = + s.Split(chars, StringSplitOptions.RemoveEmptyEntries) + + let defines = fsconfig.GetDefineSymbols() + [ + yield "--simpleresolution" + yield "--noframework" + let outputFile = project.GetOutputFileName(configSelector).ToString() + if not (String.IsNullOrWhiteSpace outputFile) then + yield "--out:" + outputFile + if Project.isPortable project || Project.isDotNetCoreProject project then + yield "--targetprofile:netcore" + if not (String.IsNullOrWhiteSpace fsconfig.PlatformTarget) then + yield "--platform:" + fsconfig.PlatformTarget + yield "--fullpaths" + yield "--flaterrors" + for symbol in defines do yield "--define:" + symbol + yield if fsconfig.HasDefineSymbol "DEBUG" then "--debug+" else "--debug-" + yield if fsconfig.Optimize then "--optimize+" else "--optimize-" + yield if fsconfig.GenerateTailCalls then "--tailcalls+" else "--tailcalls-" + if not (String.IsNullOrWhiteSpace fsconfig.DebugType) then + yield sprintf "--debug:%s" fsconfig.DebugType + yield match project.CompileTarget with + | CompileTarget.Library -> "--target:library" + | CompileTarget.Module -> "--target:module" + | _ -> "--target:exe" + yield if fsconfig.TreatWarningsAsErrors then "--warnaserror+" else "--warnaserror-" + yield sprintf "--warn:%d" fsconfig.WarningLevel + if not (String.IsNullOrWhiteSpace fsconfig.NoWarn) then + for arg in fsconfig.NoWarn |> splitByChars [|';'; ','|] do + yield "--nowarn:" + arg + // TODO: This currently ignores escaping using "..." + for arg in fsconfig.OtherFlags |> splitByChars [|' '|] do + yield arg + yield! dashr + yield! (getCompiledFiles project)] + + let generateProjectOptions (project:DotNetProject, projectAssemblyReferences: AssemblyReference seq, fsconfig:FSharpCompilerParameters, reqLangVersion, targetFramework, configSelector, shouldWrap) = + let compilerOptions = generateCompilerOptions (project, projectAssemblyReferences, fsconfig, reqLangVersion, targetFramework, configSelector, shouldWrap) |> Array.ofSeq + let loadedTimeStamp = DateTime.MaxValue // Not 'now', we don't want to force reloading + { ProjectFileName = project.FileName.FullPath.ToString() + SourceFiles = [| |] + Stamp = None + OtherOptions = compilerOptions + ReferencedProjects = [| |] + IsIncompleteTypeCheckEnvironment = false + UseScriptResolutionRules = false + LoadTime = loadedTimeStamp + UnresolvedReferences = None + OriginalLoadReferences = [] + ExtraProjectInfo = None + ProjectId = None } + + /// Get source files of the current project (returns files that have + /// build action set to 'Compile', but not e.g. scripts or resources) + let getSourceFiles (items:ProjectItemCollection) = + [ for file in items.GetAll() do + if file.BuildAction = "Compile" && file.Subtype <> Subtype.Directory then + yield file.FilePath.FullPath.ToString() ] + + + /// Generate inputs for the compiler (excluding source code!); returns list of items + /// containing resources (prefixed with the --resource parameter) + let generateOtherItems (items:ProjectItemCollection) = + [ for file in items.GetAll() do + match file.BuildAction with + | _ when file.Subtype = Subtype.Directory -> () + | "EmbeddedResource" -> + let fileName = file.Name.ToString() + let logicalResourceName = file.ProjectVirtualPath.ToString().Replace("\\",".").Replace("/",".") + yield "--resource:" + wrapFile fileName + "," + wrapFile logicalResourceName + | "None" | "Content" | "Compile" -> () + | _ -> ()] // failwith("Items of type '" + s + "' not supported") ] + + let private getToolPath (pathsToSearch:seq) (extensions:seq) (toolName:string) = + let filesToSearch = Seq.map (fun x -> toolName + x) extensions + + let tryFindPathAndFile (filesToSearch:seq) (path:string) = + try + let candidateFiles = Directory.GetFiles(path) + + let fileIfExists candidateFile = + Seq.tryFind (fun x -> Path.Combine(path,x) = candidateFile) filesToSearch + match Seq.tryPick fileIfExists candidateFiles with + | Some x -> Some(path,x) + | None -> None + + with + | e -> None + + Seq.tryPick (tryFindPathAndFile filesToSearch) pathsToSearch + + /// Get full path to tool + let getEnvironmentToolPath (runtime:TargetRuntime) (framework:TargetFramework) (extensions:seq) (toolName:string) = + + let pathsToSearch = runtime.GetToolsPaths(framework) + getToolPath pathsToSearch extensions toolName + + let private getShellToolPath (extensions:seq) (toolName:string) = + let pathVariable = Environment.GetEnvironmentVariable("PATH") + let searchPaths = pathVariable.Split [| IO.Path.PathSeparator |] + getToolPath searchPaths extensions toolName + + let getDefaultInteractive() = + + let runtime = IdeApp.Preferences.DefaultTargetRuntime.Value + let framework = Project.getDefaultTargetFramework runtime + + match getEnvironmentToolPath runtime framework [|""; ".exe"; ".bat" |] "fsharpi" with + | Some(dir,file)-> Some(Path.Combine(dir,file)) + | None-> + match getShellToolPath [| ""; ".exe"; ".bat" |] "fsharpi" with + | Some(dir,file)-> Some(Path.Combine(dir,file)) + | None-> + match getEnvironmentToolPath runtime framework [|""; ".exe"; ".bat" |] "fsi" with + | Some(dir,file)-> Some(Path.Combine(dir,file)) + | None-> + match getShellToolPath [| ""; ".exe"; ".bat" |] "fsi" with + | Some(dir,file)-> Some(Path.Combine(dir,file)) + | None-> + match FSharpEnvironment.BinFolderOfDefaultFSharpCompiler None with + | Some(dir) when FSharpEnvironment.safeExists(Path.Combine(dir, "fsi.exe")) -> + Some(Path.Combine(dir,"fsi.exe")) + | _ -> None + + let getCompilerFromEnvironment (runtime:TargetRuntime) (framework:TargetFramework) = + match getEnvironmentToolPath runtime framework [| ""; ".exe"; ".bat" |] "fsharpc" with + | Some(dir,file) -> Some(Path.Combine(dir,file)) + | None -> + match getEnvironmentToolPath runtime framework [| ""; ".exe"; ".bat" |] "fsc" with + | Some(dir,file) -> Some(Path.Combine(dir,file)) + | None -> None + + // Only used when xbuild support is not enabled. When xbuild is enabled, the .targets + // file finds FSharp.Build.dll which finds the F# compiler. + let getDefaultFSharpCompiler() = + + let runtime = IdeApp.Preferences.DefaultTargetRuntime.Value + let framework = Project.getDefaultTargetFramework runtime + + match getCompilerFromEnvironment runtime framework with + | Some(result)-> Some(result) + | None-> + match getShellToolPath [| ""; ".exe"; ".bat" |] "fsharpc" with + | Some(dir,file) -> Some(Path.Combine(dir,file)) + | None -> + match getShellToolPath [| ""; ".exe"; ".bat" |] "fsc" with + | Some(dir,file) -> Some(Path.Combine(dir,file)) + | None -> + match FSharpEnvironment.BinFolderOfDefaultFSharpCompiler None with + | Some(dir) when FSharpEnvironment.safeExists(Path.Combine(dir, "fsc.exe")) -> + Some(Path.Combine(dir,"fsc.exe")) + | _ -> None + + let getDefineSymbols (fileName:string) (project: Project) = + [if FileSystem.IsAScript fileName + then yield! ["INTERACTIVE";"EDITING"] + else yield! ["COMPILED";"EDITING"] + + let configuration = + match IdeApp.Workspace |> Option.ofNull, project |> Option.ofNull with + | None, Some proj -> + //as there is no workspace use the default configuration for the project + Some (proj.GetConfiguration(proj.DefaultConfiguration.Selector)) + | Some workspace, Some project -> + Some (project.GetConfiguration(workspace.ActiveConfiguration)) + | _ -> None + + match configuration with + | Some config -> + match config with + | :? DotNetProjectConfiguration as config -> yield! config.GetDefineSymbols() + | _ -> () + | None -> () ] + + let getConfig() = + match MonoDevelop.Ide.IdeApp.Workspace with + | ws when ws <> null && ws.ActiveConfiguration <> null -> ws.ActiveConfiguration + | _ -> MonoDevelop.Projects.ConfigurationSelector.Default + + let getArgumentsFromProject (proj:DotNetProject) (config:ConfigurationSelector) (referencedAssemblies) = + maybe { + let! projConfig = proj.GetConfiguration(config) |> Option.tryCast + let! fsconfig = projConfig.CompilationParameters |> Option.tryCast + return generateProjectOptions (proj, referencedAssemblies, fsconfig, None, getTargetFramework projConfig.TargetFramework.Id, config, false) + } + + let getReferencesFromProject (proj:DotNetProject, config:ConfigurationSelector, referencedAssemblies) = + let projConfig = proj.GetConfiguration(config) :?> DotNetProjectConfiguration + generateReferences(proj, referencedAssemblies, None, getTargetFramework projConfig.TargetFramework.Id, false) + diff --git a/vsintegration/src/FSharp.Editor/Project/FSharpProject.fs b/vsintegration/src/FSharp.Editor/Project/FSharpProject.fs new file mode 100644 index 00000000000..d6e238d71a8 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Project/FSharpProject.fs @@ -0,0 +1,348 @@ +namespace MonoDevelop.FSharp + +open System +open System.IO +open System.Threading.Tasks +open MonoDevelop.Core +open MonoDevelop.Core.Serialization +open MonoDevelop.Projects +open MonoDevelop.Projects.MSBuild +open System.Xml +open MonoDevelop.Core.Assemblies +//open ExtCore.Control + +module Project = + let FSharp3Import = "$(MSBuildExtensionsPath32)\\..\\Microsoft SDKs\\F#\\3.0\\Framework\\v4.0\\Microsoft.FSharp.Targets" + let FSharpImport = @"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets" + + let addConditionalTargets (msproject: MSBuildProject) = + let p = new MSBuildPropertyGroup() + p.SetValue("FSharpTargetsPath", FSharpImport, null, false, null) + msproject.AddPropertyGroup(p, true, null) + + let p = new MSBuildPropertyGroup() + p.Condition <- "'$(VisualStudioVersion)' == '10.0' OR '$(VisualStudioVersion)' == '11.0'" + p.SetValue("FSharpTargetsPath", FSharp3Import, null, false, null) + msproject.AddPropertyGroup(p, true, null) + +type FSharpProject() as self = + inherit DotNetProject() + do + self.RoslynLanguageName <- Microsoft.CodeAnalysis.LanguageNames.FSharp + + // Keep the platforms combo of CodeGenerationPanelWidget in sync with this list + let supportedPlatforms = [| "anycpu"; "x86"; "x64"; "Itanium" |] + + let oldFSharpProjectGuid = "{4925A630-B079-445D-BCD4-3A9C94FE9307}" + let supportedPortableProfiles = ["Profile7";"Profile47";"Profile78";"Profile259"] + + ///keyed on TargetProfile, Value: TargetFSharpCoreVersion, netcore + let profileMap = + Map.ofList ["Profile7", ("3.3.1.0", true) + "Profile47", ("2.3.5.1", false) + "Profile78", ("3.78.3.1", true) + "Profile259", ("3.259.3.1", true) ] + + let mutable initialisedAsPortable = false + + let isPortable (project:MSBuildProject) = + project.EvaluatedProperties.Properties + |> Seq.tryFind (fun i -> i.UnevaluatedValue.Equals(".NETPortable")) + |> Option.isSome + + let directoryNameFromBuildItem (item:MSBuildItem) = + let itemInclude = item.Include.Replace('\\', Path.DirectorySeparatorChar) + Path.GetDirectoryName itemInclude + + let normalizePath (path:string) = + path.Replace(Path.DirectorySeparatorChar, '\\') + + let fixProjectFormatForVisualStudio (project:MSBuildProject) = + // Merge ItemGroups into one group ordered by folder name + // so that VS for Windows can load it. + let sharedAssetFiles = CompilerArguments.getSharedAssetFilesFromReferences self + let projectPath = project.FileName.ParentDirectory |> string + let projectFiles = + self.Files + |> Seq.filter(fun f -> f.BuildAction <> "Folder" && + f.BuildAction <> "Reference" && + not (sharedAssetFiles.Contains f.FilePath) && + f.Include <> null && + (not f.IsImported)) + |> Seq.mapi(fun i f -> i, f) + |> List.ofSeq + + let absolutePath path = MSBuildProjectService.FromMSBuildPath(projectPath, path) + + let itemGroupsContainingFilesCount = + project.ItemGroups + |> Seq.map(fun group -> + group.Items + |> Seq.filter(fun item -> + projectFiles |> List.exists(fun (_i,f) -> f.Include = item.Include))) + |> Seq.choose Seq.tryHead + |> Seq.length + + let allBuildItems = + project.GetAllItems() + |> Seq.filter(fun f -> f.Name <> "Folder" && + f.Name <> "Reference" && + f.Include <> null && + (not f.IsImported)) + |> Array.ofSeq + |> Array.sortBy(fun item -> + let res = + projectFiles + |> List.tryFind(fun(_i,f) -> f.Include = normalizePath item.Include) + match res with + | Some (i,_f) -> i + | None -> Int32.MaxValue) + + + let msbuildItems = + allBuildItems + |> Array.map (fun item -> item.Include, item) + + let msbuildItemsInProjectFiles = + msbuildItems + |> List.ofSeq + |> List.map snd + + let isParentDirectory folderName fileName = + if String.isEmpty folderName then + true + else + let absoluteFolder = DirectoryInfo (absolutePath folderName) + let absoluteFile = FileInfo (absolutePath fileName) + let rec isParentDirRec (dir:DirectoryInfo) = + match dir with + | null -> false + | dir when dir.FullName = absoluteFolder.FullName -> true + | _ -> isParentDirRec dir.Parent + isParentDirRec absoluteFile.Directory + + let rec splitFilesByParent (items:MSBuildItem list) parentFolder list1 list2 = + match items with + | h :: t -> + if isParentDirectory parentFolder h.Include then + splitFilesByParent t parentFolder (h::list1) list2 + else + splitFilesByParent t parentFolder list1 (h::list2) + | [] -> (list1 |> List.rev) @ (list2 |> List.rev) + + let rec orderFiles items acc lastFolder = + match items with + | h :: t -> + let newFolder = directoryNameFromBuildItem h + if newFolder = lastFolder then + orderFiles t (h::acc) newFolder + else + let childrenFirst = (splitFilesByParent t newFolder [] []) + orderFiles childrenFirst (h::acc) newFolder + | [] -> acc |> List.rev + + let msbuildIncludes = + msbuildItemsInProjectFiles + |> List.map(fun item -> item.Name, normalizePath item.Include) + |> Set.ofList + + // Add any items that are projectFiles but not yet msbuild items to the unsorted list + // This is to fix a race condition that sometimes occurs - See #57689 + let buildItems = + projectFiles + |> List.filter(fun (_i, file) -> not (msbuildIncludes.Contains (file.BuildAction, normalizePath file.Include))) + |> List.fold(fun state (_i, file) -> + (new MSBuildItem(file.BuildAction, Include=file.Include)) :: state) msbuildItemsInProjectFiles + + let sortedItems = + orderFiles buildItems [] "" + |> List.distinctBy(fun i -> normalizePath i.Include) + + let getItemByInclude includePath = + allBuildItems |> Array.tryFind(fun item -> item.Include = includePath) + + let removeItemByInclude includePath = + getItemByInclude includePath + |> Option.iter(fun msbuildItem -> project.RemoveItem(msbuildItem, true)) + // Remove duplicate that differs only by path separator + getItemByInclude (normalizePath includePath) + |> Option.iter(fun msbuildItem -> project.RemoveItem(msbuildItem, true)) + + if itemGroupsContainingFilesCount > 1 || msbuildItemsInProjectFiles <> sortedItems then + let newGroup = project.AddNewItemGroup() + + for item in sortedItems do + removeItemByInclude item.Include + newGroup.AddItem item + + [] + member val TargetProfile = "mscorlib" with get, set + + [] + member val TargetFSharpCoreVersion = String.Empty with get, set + + [] + member val UseStandardResourceNames = true with get, set + + override x.IsPortableLibrary = initialisedAsPortable + + override x.OnReadProject(progress, project) = + initialisedAsPortable <- isPortable project + base.OnReadProject(progress, project) + + override x.OnReadProjectHeader(progress, project) = + initialisedAsPortable <- isPortable project + base.OnReadProjectHeader(progress, project) + + override x.OnSupportsFramework (framework) = + if isPortable self.MSBuildProject then + framework.Id.Identifier = TargetFrameworkMoniker.ID_PORTABLE && supportedPortableProfiles |> List.exists ((=) framework.Id.Profile) + else base.OnSupportsFramework (framework) + + override x.OnInitializeFromTemplate(createInfo, options) = + base.OnInitializeFromTemplate(createInfo, options) + if options.HasAttribute "FSharpPortable" then initialisedAsPortable <- true + if options.HasAttribute "TargetProfile" then x.TargetProfile <- options.GetAttribute "TargetProfile" + if options.HasAttribute "TargetFSharpCoreVersion" then x.TargetFSharpCoreVersion <- options.GetAttribute "TargetFSharpCoreVersion" + + override x.OnGetDefaultImports (imports) = + base.OnGetDefaultImports (imports) + + if initialisedAsPortable then + let fsharpPortableImport = + @"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.Portable.FSharp.Targets" + imports.Add(fsharpPortableImport) + else + Project.addConditionalTargets base.MSBuildProject + imports.Add("$(FSharpTargetsPath)") + + override x.OnWriteProject(monitor, msproject) = + base.OnWriteProject(monitor, msproject) + fixProjectFormatForVisualStudio msproject + let globalGroup = msproject.GetGlobalPropertyGroup() + + maybe { + //Fix pcl netcore and TargetFSharpCoreVersion + let! targetFrameworkProfile = x.TargetFramework.Id.Profile |> Option.ofString + let! fsharpcoreversion, netcore = profileMap |> Map.tryFind targetFrameworkProfile + do globalGroup.SetValue ("TargetFSharpCoreVersion", fsharpcoreversion, "", true) + let targetProfile = if netcore then "netcore" else "mscorlib" + do globalGroup.SetValue ("TargetProfile", targetProfile, "mscorlib", true) } |> ignore + + // This removes the old guid on saving the project + let removeGuid (innerText:string) guidToRemove = + innerText.Split ( [|';'|], StringSplitOptions.RemoveEmptyEntries) + |> Array.filter (fun guid -> not (guid.Equals (guidToRemove, StringComparison.OrdinalIgnoreCase))) + |> String.concat ";" + + try + let fsimportExists = + msproject.Imports + |> Seq.exists (fun import -> import.Project.EndsWith("FSharp.Targets", StringComparison.OrdinalIgnoreCase)) + if fsimportExists then + globalGroup.GetProperties() + |> Seq.tryFind (fun p -> p.Name = "ProjectTypeGuids") + |> Option.iter (fun currentGuids -> let newProjectTypeGuids = removeGuid currentGuids.Value oldFSharpProjectGuid + currentGuids.SetValue(newProjectTypeGuids)) + with exn -> LoggingService.LogWarning("Failed to remove old F# guid", exn) + + [] + override x.OnCompileSources(items, config, configSel, monitor) = + let asms = (x.GetReferences configSel).Result + CompilerService.Compile(items, config, asms, configSel, monitor) + + override x.OnCreateCompilationParameters(config, kind) = + let pars = new FSharpCompilerParameters() + config.CompilationParameters <- pars + + // Set up the default options + if supportedPlatforms |> Array.exists (fun x -> x.Contains(config.Platform)) then pars.PlatformTarget <- config.Platform + match kind with + | ConfigurationKind.Debug -> + pars.AddDefineSymbol "DEBUG" + pars.Optimize <- false + pars.GenerateTailCalls <- false + | ConfigurationKind.Release -> + pars.Optimize <- true + pars.GenerateTailCalls <- true + | _ -> () + //pars.DocumentationFile <- config.CompiledOutputName.FileNameWithoutExtension + ".xml" + pars :> DotNetCompilerParameters + + override x.OnGetSupportedClrVersions() = + [| ClrVersion.Net_2_0; ClrVersion.Net_4_0; ClrVersion.Net_4_5; ClrVersion.Clr_2_1 |] + + override x.OnFileAddedToProject(e) = + base.OnFileAddedToProject(e) + if not self.Loading then MDLanguageService.invalidateFiles e + + override x.OnFileRemovedFromProject(e) = + base.OnFileRemovedFromProject(e) + if not self.Loading then MDLanguageService.invalidateFiles e + + override x.OnFileRenamedInProject(e) = + base.OnFileRenamedInProject(e) + if not self.Loading then MDLanguageService.invalidateFiles e + + override x.OnFilePropertyChangedInProject(e) = + base.OnFilePropertyChangedInProject(e) + if not self.Loading then MDLanguageService.invalidateFiles e + + override x.OnReferenceAddedToProject(e) = + base.OnReferenceAddedToProject(e) + if not self.Loading then MDLanguageService.invalidateProjectFile self.FileName + + override x.OnReferenceRemovedFromProject(e) = + base.OnReferenceRemovedFromProject(e) + if not self.Loading then MDLanguageService.invalidateProjectFile self.FileName + + //override x.OnFileRenamedInProject(e)= + // base.OnFileRenamedInProject(e) + // if not self.Loading then invalidateProjectFile() + + override x.OnNameChanged(e)= + base.OnNameChanged(e) + if not self.Loading then MDLanguageService.invalidateProjectFile self.FileName + + override x.OnGetDefaultResourceId(projectFile) = + projectFile.FilePath.FileName + + override x.OnModified(e) = + base.OnModified(e) + if not self.Loading && not self.IsReevaluating then MDLanguageService.invalidateProjectFile self.FileName + + member x.GetOrderedReferences(config:ConfigurationSelector) = + async { + let orderAssemblyReferences = MonoDevelop.FSharp.OrderAssemblyReferences() + let! asms = x.GetReferences config + let references = + CompilerArguments.getReferencesFromProject (x, config, asms) + |> Seq.choose (fun ref -> if (ref.Contains "mscorlib.dll" || ref.Contains "FSharp.Core.dll") + then None + else + let ref = ref |> String.replace "-r:" "" + if File.Exists ref then Some ref + else None ) + |> Seq.distinct + |> Seq.toArray + return orderAssemblyReferences.Order references + } + + member x.ReevaluateProject(e) = + let task = base.OnReevaluateProject (e) + + async { + do! task + MDLanguageService.invalidateProjectFile self.FileName + } + + override x.OnReevaluateProject(monitor) = + x.ReevaluateProject monitor |> StartAsyncAsTask monitor.CancellationToken :> Task + + override x.OnDispose () = + languageService.HideStatusIcon (string self.FileName.FullPath) + // FIXME: is it correct to do it every time a project is disposed? + //Should only be done on solution close + //langServ.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() + base.OnDispose () + diff --git a/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs b/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs new file mode 100644 index 00000000000..8b160b6e906 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs @@ -0,0 +1,17 @@ +namespace Microsoft.VisualStudio.FSharp.Editor +open Mono.Addins + +[] + +[] +[] +[] + +//[] +//[] + +() \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index d75971c53ce..cc4c42abe8c 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -15,7 +15,7 @@ open Microsoft.VisualStudio.Language.Intellisense open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.Text -//open Microsoft.VisualStudio.Utilities +open Microsoft.VisualStudio.Utilities open FSharp.Compiler.SourceCodeServices open FSharp.Compiler.Range @@ -160,7 +160,7 @@ module internal FSharpQuickInfo = type internal FSharpAsyncQuickInfoSource ( statusBar: StatusBar, - xmlMemberIndexService: IVsXMLMemberIndexService, + //xmlMemberIndexService: IVsXMLMemberIndexService, checkerProvider:FSharpCheckerProvider, projectInfoManager:FSharpProjectOptionsManager, textBuffer:ITextBuffer, @@ -215,7 +215,7 @@ type internal FSharpAsyncQuickInfoSource | false -> Task.FromResult(null) | true -> let triggerPoint = triggerPoint.GetValueOrDefault() - let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder(xmlMemberIndexService) + let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder((*xmlMemberIndexService*)) asyncMaybe { let document = textBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges() let! symbolUse, sigQuickInfo, targetQuickInfo = FSharpQuickInfo.getQuickInfo(checkerProvider.Checker, projectInfoManager, document, triggerPoint.Position, cancellationToken) @@ -233,9 +233,9 @@ type internal FSharpAsyncQuickInfoSource let span = getTrackingSpan quickInfo.Span return QuickInfoItem(span, content) - | Some sigQuickInfo, Some targetQuickInfo -> + | Some _sigQuickInfo, Some targetQuickInfo -> let mainDescription, targetDocumentation, sigDocumentation, typeParameterMap, exceptions, usage = ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray() - XmlDocumentation.BuildDataTipText(documentationBuilder, ignore, sigDocumentation.Add, ignore, ignore, ignore, sigQuickInfo.StructuredText) + //XmlDocumentation.BuildDataTipText(documentationBuilder, ignore, sigDocumentation.Add, ignore, ignore, ignore, sigQuickInfo.StructuredText) XmlDocumentation.BuildDataTipText(documentationBuilder, mainDescription.Add, targetDocumentation.Add, typeParameterMap.Add, exceptions.Add, usage.Add, targetQuickInfo.StructuredText) // get whitespace nomalized documentation text let getText (tts: seq) = @@ -266,13 +266,13 @@ type internal FSharpAsyncQuickInfoSource |> RoslynHelpers.StartAsyncAsTask cancellationToken [)>] -//[] -//[] -//[] +[] +[] +[] type internal FSharpAsyncQuickInfoSourceProvider [] ( - [)>] serviceProvider: IServiceProvider, + //[)>] serviceProvider: IServiceProvider, checkerProvider:FSharpCheckerProvider, projectInfoManager:FSharpProjectOptionsManager, settings: EditorOptions @@ -282,6 +282,6 @@ type internal FSharpAsyncQuickInfoSourceProvider override __.TryCreateQuickInfoSource(textBuffer:ITextBuffer) : IAsyncQuickInfoSource = // GetService calls must be made on the UI thread // It is safe to do it here (see #4713) - let statusBar = StatusBar(serviceProvider.GetService()) - let xmlMemberIndexService = serviceProvider.XMLMemberIndexService - new FSharpAsyncQuickInfoSource(statusBar, xmlMemberIndexService, checkerProvider, projectInfoManager, textBuffer, settings) :> IAsyncQuickInfoSource + let statusBar = StatusBar((*serviceProvider.GetService()*)) + //let xmlMemberIndexService = serviceProvider.XMLMemberIndexService + new FSharpAsyncQuickInfoSource(statusBar, (* xmlMemberIndexService,*) checkerProvider, projectInfoManager, textBuffer, settings) :> IAsyncQuickInfoSource From 8299f5f5b03055f19393f3fff9e52b47d69185c1 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 16 Dec 2019 18:02:03 +0000 Subject: [PATCH 004/101] stash --- .../src/FSharp.Editor/Common/Constants.fs | 2 +- .../Completion/CompletionService.fs | 2 +- .../src/FSharp.Editor/FSharp.Editor.fsproj | 37 ++++++++++--------- .../src/FSharp.Editor/FSharp.addin.xml | 2 +- .../LanguageService/FSharpContentType.fs | 18 +++++++++ .../Navigation/GoToDefinition.fs | 21 ++++++----- .../QuickInfo/QuickInfoProvider.fs | 1 + 7 files changed, 52 insertions(+), 31 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs diff --git a/vsintegration/src/FSharp.Editor/Common/Constants.fs b/vsintegration/src/FSharp.Editor/Common/Constants.fs index 0323cd11862..2c6e7c58fdc 100644 --- a/vsintegration/src/FSharp.Editor/Common/Constants.fs +++ b/vsintegration/src/FSharp.Editor/Common/Constants.fs @@ -29,7 +29,7 @@ module internal FSharpConstants = [] /// "F#" - let FSharpContentTypeName = "code++.F#" + let FSharpContentTypeName = "F#" [] /// ".fs" diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index c8de0d91dae..a711cc9a842 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -66,7 +66,7 @@ type internal FSharpCompletionService [] -[, FSharpConstants.FSharpLanguageName)>] +[, FSharpConstants.FSharpContentTypeName)>] type internal FSharpCompletionServiceFactory [] ( diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index f3ddfb59df9..42294cc344f 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -85,6 +85,7 @@ + @@ -166,8 +167,6 @@ - - @@ -176,31 +175,33 @@ - - + + - + - + - - - - - + + + + + + + + + + + + + - - - - - - - + \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index d5c7f2af191..b11b05405f0 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -6,7 +6,7 @@ - + diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs new file mode 100644 index 00000000000..33c7a96030d --- /dev/null +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs @@ -0,0 +1,18 @@ +namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +open System.ComponentModel.Composition +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +open Microsoft.VisualStudio.Utilities + +type FSharpContentTypeDefinitions() = + let _x = 1 + [] + [] + [] + member val FSharpContentTypeDefinition: ContentTypeDefinition = null with get, set + + [] + [] + [] + member val FSharpSignatureHelpContentTypeDefinition: ContentTypeDefinition = null with get, set diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs index 7891cd8a0ed..f8455527f54 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs @@ -16,7 +16,7 @@ open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.Navigation open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Navigation -open Microsoft.VisualStudio.Shell.Interop +//open Microsoft.VisualStudio.Shell.Interop open FSharp.Compiler.Range open FSharp.Compiler.SourceCodeServices @@ -108,15 +108,16 @@ module private ExternalSymbol = // TODO: Uncomment code when VS has a fix for updating the status bar. type internal StatusBar((*statusBar: IVsStatusbar*)) = - let mutable _searchIcon = int16 Microsoft.VisualStudio.Shell.Interop.Constants.SBAI_Find :> obj + //let mutable _searchIcon = int16 Microsoft.VisualStudio.Shell.Interop.Constants.SBAI_Find :> obj - let _clear() = () + let clear() = + MonoDevelop.Ide.IdeApp.Workbench.StatusBar.ShowReady() // unfreeze the statusbar //statusBar.FreezeOutput 0 |> ignore //statusBar.Clear() |> ignore - - member __.Message(_msg: string) = - () + + member __.Message(msg: string) = + MonoDevelop.Ide.IdeApp.Workbench.StatusBar.ShowMessage(msg) //let _, frozen = statusBar.IsFrozen() //// unfreeze the status bar //if frozen <> 0 then statusBar.FreezeOutput 0 |> ignore @@ -124,8 +125,8 @@ type internal StatusBar((*statusBar: IVsStatusbar*)) = //// freeze the status bar //statusBar.FreezeOutput 1 |> ignore - member this.TempMessage(_msg: string) = - () + member this.TempMessage(msg: string) = + this.Message(msg) //this.Message msg //async { // do! Async.Sleep 4000 @@ -133,8 +134,8 @@ type internal StatusBar((*statusBar: IVsStatusbar*)) = // | 0, currentText when currentText <> msg -> () // | _ -> clear() //}|> Async.Start - - member __.Clear() = () //clear() + + member __.Clear() = clear() /// Animated magnifying glass that displays on the status bar while a symbol search is in progress. member __.Animate() : IDisposable = diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index cc4c42abe8c..83dbab3a68b 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -22,6 +22,7 @@ open FSharp.Compiler.Range open FSharp.Compiler open Internal.Utilities.StructuredFormat +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion type internal QuickInfo = { StructuredText: FSharpStructuredToolTipText From 69c9b75533f92b348bd163d0ac011dceb963c229 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 16 Dec 2019 18:02:13 +0000 Subject: [PATCH 005/101] stash --- .../src/FSharp.Editor/FSharp.Editor.sln | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 vsintegration/src/FSharp.Editor/FSharp.Editor.sln diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.sln b/vsintegration/src/FSharp.Editor/FSharp.Editor.sln new file mode 100644 index 00000000000..381c69dad79 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.sln @@ -0,0 +1,33 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Editor", "FSharp.Editor.fsproj", "{3F4888DE-589A-4DD6-84CC-DDBE6F87A72C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4A2F4F15-F535-4A18-B36C-F1F9080B6794}" + ProjectSection(SolutionItems) = preProject + ..\Directory.Build.props = ..\Directory.Build.props + ..\..\..\FSharp.Profiles.props = ..\..\..\FSharp.Profiles.props + ..\..\..\FSharpBuild.Directory.Build.props = ..\..\..\FSharpBuild.Directory.Build.props + ..\..\..\global.json = ..\..\..\global.json + ..\..\..\NuGet.config = ..\..\..\NuGet.config + ..\..\..\restore.sh = ..\..\..\restore.sh + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Proto|Any CPU = Proto|Any CPU + DebugMac|Any CPU = DebugMac|Any CPU + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3F4888DE-589A-4DD6-84CC-DDBE6F87A72C}.Proto|Any CPU.ActiveCfg = Proto|Any CPU + {3F4888DE-589A-4DD6-84CC-DDBE6F87A72C}.Proto|Any CPU.Build.0 = Proto|Any CPU + {3F4888DE-589A-4DD6-84CC-DDBE6F87A72C}.DebugMac|Any CPU.ActiveCfg = DebugMac|Any CPU + {3F4888DE-589A-4DD6-84CC-DDBE6F87A72C}.DebugMac|Any CPU.Build.0 = DebugMac|Any CPU + {3F4888DE-589A-4DD6-84CC-DDBE6F87A72C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3F4888DE-589A-4DD6-84CC-DDBE6F87A72C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F4888DE-589A-4DD6-84CC-DDBE6F87A72C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3F4888DE-589A-4DD6-84CC-DDBE6F87A72C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal From 0fe661b3f3c74e1f87f0e8684f9570d7a3aa18d5 Mon Sep 17 00:00:00 2001 From: nosami Date: Sat, 28 Dec 2019 20:30:41 +0000 Subject: [PATCH 006/101] stash --- src/buildtools/fslex/fslex.fsproj | 2 +- src/buildtools/fsyacc/fsyacc.fsproj | 2 +- .../ClassificationDefinitions.fs | 6 +- .../Classification/ClassificationService.fs | 3 +- .../Completion/CompletionService.fs | 22 +++---- .../src/FSharp.Editor/FSharp.Editor.fsproj | 52 ++++++++-------- .../FSharpProjectOptionsManager.fs | 38 ++++++------ .../Navigation/GoToDefinitionService.fs | 59 +++++++++++++++++++ .../FSharp.Editor/Options/EditorOptionsMac.fs | 2 +- 9 files changed, 124 insertions(+), 62 deletions(-) diff --git a/src/buildtools/fslex/fslex.fsproj b/src/buildtools/fslex/fslex.fsproj index e348901415c..349d981c4a1 100644 --- a/src/buildtools/fslex/fslex.fsproj +++ b/src/buildtools/fslex/fslex.fsproj @@ -2,7 +2,7 @@ Exe - net472;netcoreapp2.1 + net472 INTERNALIZED_FSLEXYACC_RUNTIME;$(DefineConstant) true diff --git a/src/buildtools/fsyacc/fsyacc.fsproj b/src/buildtools/fsyacc/fsyacc.fsproj index e21a730c617..a52a70c96da 100644 --- a/src/buildtools/fsyacc/fsyacc.fsproj +++ b/src/buildtools/fsyacc/fsyacc.fsproj @@ -2,7 +2,7 @@ Exe - net472;netcoreapp2.1 + net472 INTERNALIZED_FSLEXYACC_RUNTIME;$(DefineConstant) true diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs index 23e72a35629..c65f0c70f0c 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs @@ -9,9 +9,9 @@ open System.Windows.Media open Microsoft.VisualStudio open Microsoft.VisualStudio.Editor //open Microsoft.VisualStudio.PlatformUI -open Microsoft.VisualStudio.Shell -open Microsoft.VisualStudio.Shell.Interop -open Microsoft.Internal.VisualStudio.Shell.Interop +//open Microsoft.VisualStudio.Shell +//open Microsoft.VisualStudio.Shell.Interop +//open Microsoft.Internal.VisualStudio.Shell.Interop open Microsoft.VisualStudio.Language.StandardClassification open Microsoft.VisualStudio.Text.Classification //open Microsoft.VisualStudio.Utilities diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs index d950a0abbf5..bb5aabad780 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs @@ -63,7 +63,8 @@ type internal FSharpClassificationService match classificationType with | SemanticClassificationType.Printf -> span | _ -> Tokenizer.fixupSpan(sourceText, span) - result.Add(ClassifiedSpan(span, FSharpClassificationTypes.getClassificationTypeName(classificationType))) + //result.Add(ClassifiedSpan(span, FSharpClassificationTypes.getClassificationTypeName(classificationType))) + result.Add(ClassifiedSpan(span, classificationType.ToString())) } |> Async.Ignore |> RoslynHelpers.StartAsyncUnitAsTask cancellationToken diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index a711cc9a842..310e1ba99f3 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -66,21 +66,23 @@ type internal FSharpCompletionService [] -[, FSharpConstants.FSharpContentTypeName)>] +//[, FSharpConstants.FSharpContentTypeName)>] +[, "code++.F#")>] + type internal FSharpCompletionServiceFactory [] ( //serviceProvider: SVsServiceProvider, - _checkerProvider: FSharpCheckerProvider + checkerProvider: FSharpCheckerProvider, - //projectInfoManager: FSharpProjectOptionsManager, - //assemblyContentProvider: AssemblyContentProvider, - //settings: EditorOptions + projectInfoManager: FSharpProjectOptionsManager, + assemblyContentProvider: AssemblyContentProvider, + settings: EditorOptions ) = - member x.X = 1 - //interface ILanguageServiceFactory with - //member this.CreateLanguageService(hostLanguageServices: HostLanguageServices) : ILanguageService = - //upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, projectInfoManager, assemblyContentProvider, settings) - ////upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, new FSharpProjectOptionsManager(, assemblyContentProvider, settings) + + interface ILanguageServiceFactory with + member this.CreateLanguageService(hostLanguageServices: HostLanguageServices) : ILanguageService = + upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, projectInfoManager, assemblyContentProvider, settings) + //upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, new FSharpProjectOptionsManager(, assemblyContentProvider, settings) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 42294cc344f..e12365fae2e 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -48,10 +48,10 @@ - + - + @@ -108,7 +108,7 @@ $(VSAssemblyVersion) $PackageFolder$\FSharp.Editor.dll - + @@ -167,41 +167,41 @@ - - - - Common\LspExternalAccess.fs - - - - - - - - - - - - - - - - - + - - + + + + + + Common\LspExternalAccess.fs + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index 7fcb671b444..b491d01391d 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -15,9 +15,9 @@ open Microsoft.VisualStudio open Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.LanguageServices open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem -open Microsoft.VisualStudio.Shell +//open Microsoft.VisualStudio.Shell open System.Threading -open Microsoft.VisualStudio.Shell.Interop +//open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.LanguageServices.Implementation.TaskList open Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices @@ -152,16 +152,16 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) // Because this code can be kicked off before the hack, HandleCommandLineChanges, occurs, // the command line options will not be available and we should bail if one of the project references does not give us anything. let mutable canBail = false - - let referencedProjects = ResizeArray() - if settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences then - for projectReference in project.ProjectReferences do - let referencedProject = project.Solution.GetProject(projectReference.ProjectId) - if referencedProject.Language = FSharpConstants.FSharpLanguageName then - match! tryComputeOptions referencedProject with - | None -> canBail <- true - | Some(_, projectOptions) -> referencedProjects.Add(referencedProject.OutputFilePath, projectOptions) + //let referencedProjects = ResizeArray() + + //if settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences then + //for projectReference in project.ProjectReferences do + //let referencedProject = project.Solution.GetProject(projectReference.ProjectId) + //if referencedProject.Language = FSharpConstants.FSharpLanguageName then + //match! tryComputeOptions referencedProject with + //| None -> canBail <- true + //| Some(_, projectOptions) -> referencedProjects.Add(referencedProject.OutputFilePath, projectOptions) if canBail then return None @@ -237,7 +237,7 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) if ct.IsCancellationRequested then reply.Reply None else - try + //try // For now, disallow miscellaneous workspace since we are using the hacky F# miscellaneous files project. if document.Project.Solution.Workspace.Kind = WorkspaceKind.MiscellaneousFiles then reply.Reply None @@ -247,23 +247,23 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) else let! options = tryComputeOptions document.Project reply.Reply options - with - | _ -> - reply.Reply None + //with + //| _ -> + //reply.Reply None | FSharpProjectOptionsMessage.TryGetOptionsByProject(project, reply, ct) -> if ct.IsCancellationRequested then reply.Reply None else - try + //try if project.Solution.Workspace.Kind = WorkspaceKind.MiscellaneousFiles || project.Name = FSharpConstants.FSharpMiscellaneousFilesName then reply.Reply None else let! options = tryComputeOptions project reply.Reply options - with - | _ -> - reply.Reply None + //with + //| _ -> + //reply.Reply None | FSharpProjectOptionsMessage.ClearOptions(projectId) -> cache.Remove(projectId) |> ignore diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs index 003f338e179..3c246cbca97 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs @@ -14,7 +14,66 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio.Shell.Interop open System +open System; +open System.ComponentModel.Composition; +open Microsoft.CodeAnalysis.Editor.Shared.Extensions; +open Microsoft.CodeAnalysis.Notification; +open Microsoft.CodeAnalysis.Shared.Extensions; +open Microsoft.CodeAnalysis.Text; +open Microsoft.VisualStudio.Commanding; +open Microsoft.VisualStudio.Text; +open Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +open Microsoft.VisualStudio.Utilities; +[)>] +[] +[] +type internal FSharpGotoDefinitionCommandHandler + [] + ( + checkerProvider: FSharpCheckerProvider, + projectInfoManager: FSharpProjectOptionsManager + ) = + + let gtd = GoToDefinition(checkerProvider.Checker, projectInfoManager) + let statusBar = StatusBar((*ServiceProvider.GlobalProvider.GetService()*)) + interface ICommandHandler with + member __.DisplayName = "FSharp Go To Definition" + member __.GetCommandState(_args) = + CommandState.Available + + member __.ExecuteCommand(args, context) = + statusBar.Message(SR.LocatingSymbol()) + let subjectBuffer = args.SubjectBuffer + let document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges() + use __ = statusBar.Animate() + + let position = args.TextView.Caret.Position.Point.GetPoint(subjectBuffer, PositionAffinity.Predecessor).Value.Position + let gtdTask = gtd.FindDefinitionTask(document, position, context.OperationContext.UserCancellationToken) + + // Wrap this in a try/with as if the user clicks "Cancel" on the thread dialog, we'll be cancelled. + // Task.Wait throws an exception if the task is cancelled, so be sure to catch it. + try + // This call to Wait() is fine because we want to be able to provide the error message in the status bar. + gtdTask.Wait() + if gtdTask.Status = TaskStatus.RanToCompletion && gtdTask.Result.IsSome then + let item, _ = gtdTask.Result.Value + gtd.NavigateToItem(item, statusBar) + + // 'true' means do it, like Sheev Palpatine would want us to. + true + else + statusBar.TempMessage (SR.CannotDetermineSymbol()) + false + with exc -> + statusBar.TempMessage(String.Format(SR.NavigateToFailed(), Exception.flattenMessage exc)) + + // Don't show the dialog box as it's most likely that the user cancelled. + // Don't make them click twice. + true + //use __ = statusBar.Animate() + + //args.SubjectBuffer. [)>] [)>] type internal FSharpGoToDefinitionService diff --git a/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs b/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs index f7a697342fc..ab92c7a72ee 100644 --- a/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs +++ b/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs @@ -65,7 +65,7 @@ type LanguageServicePerformanceOptions = TimeUntilStaleCompletion: int ProjectCheckCacheSize: int } static member Default = - { EnableInMemoryCrossProjectReferences = true + { EnableInMemoryCrossProjectReferences = false AllowStaleCompletionResults = true TimeUntilStaleCompletion = 2000 // In ms, so this is 2 seconds ProjectCheckCacheSize = 200 } From 397f2f3e0f5b97024a5d74d7540c65ae05080e28 Mon Sep 17 00:00:00 2001 From: nosami Date: Sun, 5 Jan 2020 11:55:40 +0000 Subject: [PATCH 007/101] Commit manager --- .../AsyncCompletionCommitManager.fs | 93 ++++++++ .../AsyncCompletionCommitManagerProvider.fs | 23 ++ .../Completion/CompletionProvider.fs | 81 ++++--- .../Completion/CompletionService.fs | 220 ++++++++++++++++++ .../Completion/CompletionUtils.fs | 63 ++++- .../FSharp.Editor/FSharp.Editor.Designer.fs | 2 +- .../src/FSharp.Editor/FSharp.Editor.fsproj | 86 +++---- .../FSharp.Editor/Options/EditorOptionsMac.fs | 5 +- .../QuickInfo/QuickInfoProvider.fs | 4 +- 9 files changed, 493 insertions(+), 84 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManager.fs create mode 100644 vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManagerProvider.fs diff --git a/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManager.fs b/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManager.fs new file mode 100644 index 00000000000..b75bcebe680 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManager.fs @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion +open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data + +type FSharpAsyncCompletionCommitManager() = + interface IAsyncCompletionCommitManager with + + /// + /// + /// Returns characters that may commit completion. + /// + /// + /// When completion is active and a text edit matches one of these characters, + /// is called to verify that the character + /// is indeed a commit character at a given location. + /// + /// + /// Called on UI thread. + /// + /// + override __.PotentialCommitCharacters = [' '; '='; ','; '.'; '<'; '>'; '('; ')'; '!'; ':'; '['; ']'; '|'] |> Seq.ofList + + /// + /// + /// Returns whether is a commit character at a given . + /// + /// + /// If in your language every character returned by + /// is a commit character, simply return . + /// + /// + /// Called on UI thread. + /// + /// + /// The active + /// Location in the snapshot of the view's topmost buffer. The character is not inserted into this snapshot + /// Character typed by the user + /// Token used to cancel this operation + /// True if this character should commit the active session + override __.ShouldCommitCompletion(session, location, typedChar, token) = true + + /// + /// + /// Allows the implementer of to customize how specified is committed. + /// This method is called on UI thread, before the is inserted into the buffer. + /// + /// + /// In most cases, implementer does not need to commit the item. Return to allow another + /// to attempt the commit, or to invoke the default commit behavior. + /// + /// + /// To perform a custom commit, replace contents of + /// at a location indicated by + /// with text stored in . + /// To move the caret, use . + /// Finally, return . Use to influence Editor's behavior + /// after invoking this method. + /// + /// + /// Called on UI thread. + /// + /// + /// The active . See and + /// Subject buffer which matches this 's content type + /// Which is to be committed + /// Text change associated with this commit + /// Token used to cancel this operation + /// Instruction for the editor how to proceed after invoking this method. Default is + override __.TryCommit(session, buffer, item, typedChar, token) = CommitResult.Unhandled + + +open System.Composition +open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion +open Microsoft.VisualStudio.Utilities +open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.Text.Editor +[)>] +[] +[] +//[] +//[] +type internal FSharpAsyncCompletionCommitManagerProvider3 + [] + ( + checkerProvider: FSharpCheckerProvider + ) = + let x = 1 + interface IAsyncCompletionCommitManagerProvider with + member __.GetOrCreate(textView) = + System.Diagnostics.Trace.WriteLine("GetOrCreate FSharpAsyncCompletionCommitManager") + FSharpAsyncCompletionCommitManager() :> _ \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManagerProvider.fs b/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManagerProvider.fs new file mode 100644 index 00000000000..a4e70e2870c --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManagerProvider.fs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.VisualStudio.FSharp.Editor.GRRRRR + +open System.Composition +open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion +open Microsoft.VisualStudio.Utilities +open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.Text.Editor + +[)>] +[] +[] +//[] +//[] +type FSharpAsyncCompletionCommitManagerProvider() = + //[] + //() = + let x = 1 + interface IAsyncCompletionCommitManagerProvider with + member __.GetOrCreate(textView) = + System.Diagnostics.Trace.WriteLine("GetOrCreate FSharpAsyncCompletionCommitManager") + FSharpAsyncCompletionCommitManager() :> _ \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index 3d57ba59ac5..bd78f7a614d 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -19,6 +19,7 @@ open Microsoft.VisualStudio.Shell open FSharp.Compiler open FSharp.Compiler.Range open FSharp.Compiler.SourceCodeServices +open Microsoft.VisualStudio.Text.Adornments module Logger = Microsoft.VisualStudio.FSharp.Editor.Logger @@ -48,10 +49,7 @@ type internal FSharpCompletionProvider Keywords.KeywordsWithDescription |> List.filter (fun (keyword, _) -> not (PrettyNaming.IsOperatorName keyword)) |> List.sortBy (fun (keyword, _) -> keyword) - |> List.mapi (fun n (keyword, description) -> - FSharpCommonCompletionItem.Create(keyword, null, CompletionItemRules.Default, Nullable Glyph.Keyword, sortText = sprintf "%06d" (1000000 + n)) - .AddProperty("description", description) - .AddProperty(IsKeywordPropName, "")) + let checker = checkerProvider.Checker @@ -101,7 +99,7 @@ type internal FSharpCompletionProvider (triggerChar = '.' || (intelliSenseOptions.ShowAfterCharIsTyped && CompletionUtils.isStartingNewWord(sourceText, triggerPosition))) - static member ProvideCompletionsAsyncAux(checker: FSharpChecker, sourceText: SourceText, caretPosition: int, options: FSharpProjectOptions, filePath: string, + static member ProvideCompletionsAsyncAux(completionSource: Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.IAsyncCompletionSource , checker: FSharpChecker, sourceText: SourceText, caretPosition: int, options: FSharpProjectOptions, filePath: string, textVersionHash: int, getAllSymbols: FSharpCheckFileResults -> AssemblySymbol list, languageServicePerformanceOptions: LanguageServicePerformanceOptions, intellisenseOptions: IntelliSenseOptions) = asyncMaybe { let! parseResults, _, checkFileResults = checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, options, languageServicePerformanceOptions, userOpName = userOpName) @@ -120,7 +118,7 @@ type internal FSharpCompletionProvider let! declarations = checkFileResults.GetDeclarationListInfo(Some(parseResults), fcsCaretLineNumber, caretLine.ToString(), partialName, getAllSymbols, userOpName=userOpName) |> liftAsync - let results = List() + let results = List() declarationItems <- declarations.Items @@ -152,27 +150,28 @@ type internal FSharpCompletionProvider // We are passing last part of long ident as FilterText. | _, idents -> Array.last idents - let completionItem = - FSharpCommonCompletionItem.Create(name, null, rules = getRules intellisenseOptions.ShowAfterCharIsTyped, glyph = Nullable glyph, filterText = filterText) - .AddProperty(FullNamePropName, declarationItem.FullName) + let completionItem = + new Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem(name, completionSource) + //FSharpCommonCompletionItem.Create(name, null, rules = getRules intellisenseOptions.ShowAfterCharIsTyped, glyph = Nullable glyph, filterText = filterText) + //.AddProperty(FullNamePropName, declarationItem.FullName) let completionItem = match declarationItem.Kind with | CompletionItemKind.Method (isExtension = true) -> - completionItem.AddProperty(IsExtensionMemberPropName, "") + completionItem//.AddProperty(IsExtensionMemberPropName, "") | _ -> completionItem let completionItem = if name <> declarationItem.NameInCode then - completionItem.AddProperty(NameInCodePropName, declarationItem.NameInCode) + completionItem//.AddProperty(NameInCodePropName, declarationItem.NameInCode) else completionItem let completionItem = match declarationItem.NamespaceToOpen with - | Some ns -> completionItem.AddProperty(NamespaceToOpenPropName, ns) + | Some ns -> completionItem//.AddProperty(NamespaceToOpenPropName, ns) | None -> completionItem - let completionItem = completionItem.AddProperty(IndexPropName, string number) + let completionItem = completionItem//.AddProperty(IndexPropName, string number) let priority = match mruItems.TryGetValue declarationItem.FullName with @@ -180,21 +179,31 @@ type internal FSharpCompletionProvider | _ -> number + maxHints + 1 let sortText = priority.ToString("D6") - let completionItem = completionItem.WithSortText(sortText) + let completionItem = completionItem//.WithSortText(sortText) results.Add(completionItem)) if results.Count > 0 && not declarations.IsForType && not declarations.IsError && List.isEmpty partialName.QualifyingIdents then let lineStr = textLines.[caretLinePos.Line].ToString() - + let completionContext = parseResults.ParseTree |> Option.bind (fun parseTree -> UntypedParseImpl.TryGetCompletionContext(Pos.fromZ caretLinePos.Line caretLinePos.Character, parseTree, lineStr)) - + + let keywordGlyph = ExternalAccess.FSharp.FSharpGlyph.Keyword match completionContext with - | None -> results.AddRange(keywordCompletionItems) + | None -> + let keywordItemsWithSource = + keywordCompletionItems + |> List.mapi (fun n (keyword, description) -> + new Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem + (keyword, completionSource, null, ImmutableArray.Empty, "", keyword, sprintf "%06d" (1000000 + n), keyword, keyword, ImmutableArray.Empty )) + //FSharpCommonCompletionItem.Create(keyword, null, CompletionItemRules.Default, Nullable Glyph.Keyword, )) + //.AddProperty("description", description) + //.AddProperty(IsKeywordPropName, "")) + results.AddRange(keywordItemsWithSource) | _ -> () - + return results } @@ -208,26 +217,26 @@ type internal FSharpCompletionProvider (documentId, document.FilePath, defines) FSharpCompletionProvider.ShouldTriggerCompletionAux(sourceText, caretPosition, trigger.Kind, getInfo, settings.IntelliSense) - + override this.ProvideCompletionsAsync(context: Completion.CompletionContext) = asyncMaybe { - use _logBlock = Logger.LogBlockMessage context.Document.Name LogEditorFunctionId.Completion_ProvideCompletionsAsync - - let document = context.Document - let! sourceText = context.Document.GetTextAsync(context.CancellationToken) - let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) - do! Option.guard (CompletionUtils.shouldProvideCompletion(document.Id, document.FilePath, defines, sourceText, context.Position)) - let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken) - let! textVersion = context.Document.GetTextVersionAsync(context.CancellationToken) - let getAllSymbols(fileCheckResults: FSharpCheckFileResults) = - if settings.IntelliSense.IncludeSymbolsFromUnopenedNamespacesOrModules - then assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies(fileCheckResults) - else [] - let! results = - FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, sourceText, context.Position, projectOptions, document.FilePath, - textVersion.GetHashCode(), getAllSymbols, settings.LanguageServicePerformance, settings.IntelliSense) - - context.AddItems(results) + //use _logBlock = Logger.LogBlockMessage context.Document.Name LogEditorFunctionId.Completion_ProvideCompletionsAsync + + //let document = context.Document + //let! sourceText = context.Document.GetTextAsync(context.CancellationToken) + //let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) + //do! Option.guard (CompletionUtils.shouldProvideCompletion(document.Id, document.FilePath, defines, sourceText, context.Position)) + //let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken) + //let! textVersion = context.Document.GetTextVersionAsync(context.CancellationToken) + //let getAllSymbols(fileCheckResults: FSharpCheckFileResults) = + // if settings.IntelliSense.IncludeSymbolsFromUnopenedNamespacesOrModules + // then assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies(fileCheckResults) + // else [] + //let! results = + //FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, sourceText, context.Position, projectOptions, document.FilePath, + //textVersion.GetHashCode(), getAllSymbols, settings.LanguageServicePerformance, settings.IntelliSense) + + context.AddItems([])//results) } |> Async.Ignore |> RoslynHelpers.StartAsyncUnitAsTask context.CancellationToken override this.GetDescriptionAsync(document: Document, completionItem: Completion.CompletionItem, cancellationToken: CancellationToken): Task = diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index 310e1ba99f3..59f90e7068a 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -13,6 +13,50 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion open Microsoft.VisualStudio.Shell + + +open System +open System.ComponentModel.Composition +open Microsoft.CodeAnalysis.Editor.Host +open Microsoft.CodeAnalysis.Editor.Shared.Utilities +open Microsoft.CodeAnalysis.Host.Mef +open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion +open Microsoft.VisualStudio.Text.Editor +open Microsoft.VisualStudio.Utilities +open System.Threading.Tasks + +open System; +open System.Collections.Generic; +open System.Collections.Immutable; +open System.Collections.Specialized; +open System.Linq; +open System.Runtime.CompilerServices; +open System.Threading; +open System.Threading.Tasks; +open Microsoft.CodeAnalysis.Completion; +open Microsoft.CodeAnalysis.Completion.Providers; +open Microsoft.CodeAnalysis.Editor.Host; +open Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion; +open Microsoft.CodeAnalysis.Editor.Shared.Extensions; +open Microsoft.CodeAnalysis.Editor.Shared.Utilities; +open Microsoft.CodeAnalysis.Experiments; +open Microsoft.CodeAnalysis.LanguageServices; +open Microsoft.CodeAnalysis.PooledObjects; +open Microsoft.CodeAnalysis.Shared.Extensions; +open Microsoft.CodeAnalysis.Text; +open Microsoft.CodeAnalysis.Text.Shared.Extensions; +open Microsoft.VisualStudio.Core.Imaging; +open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; +open Microsoft.VisualStudio.Text; +open Microsoft.VisualStudio.Text.Adornments; + +open FSharp.Compiler +open FSharp.Compiler.Range +open FSharp.Compiler.SourceCodeServices +//open Microsoft.VisualStudio.Text.Editor; +//open AsyncCompletionData = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; +//open RoslynCompletionItem = Microsoft.CodeAnalysis.Completion.CompletionItem; +//open VSCompletionItem = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem; type internal FSharpCompletionService ( workspace: Workspace, @@ -85,4 +129,180 @@ type internal FSharpCompletionServiceFactory upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, projectInfoManager, assemblyContentProvider, settings) //upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, new FSharpProjectOptionsManager(, assemblyContentProvider, settings) +type internal FSharpCompletionSource + (textView: ITextView, checkerProvider, projectInfoManager, assemblyContentProvider) = + + + let settings: EditorOptions = textView.TextBuffer.GetWorkspace().Services.GetService() + + /// + /// Called when user interacts with expander buttons, + /// requesting the completion source to provide additional completion items pertinent to the expander button. + /// For best performance, do not provide unless expansion should add new filters. + /// Called on a background thread. + /// + /// Reference to the active + /// Expander which caused this call + /// What initially caused the completion + /// Location where completion will take place, on the view's data buffer: + /// Cancellation token that may interrupt this operation + /// A struct that holds completion items and applicable span + //Task GetExpandedCompletionContextAsync( + //IAsyncCompletionSession session, + //CompletionExpander expander, + //CompletionTrigger initialTrigger, + //SnapshotSpan applicableToSpan, + //CancellationToken token); + let commitChars = [|' '; '='; ','; '.'; '<'; '>'; '('; ')'; '!'; ':'; '['; ']'; '|'|].ToImmutableArray() + interface IAsyncExpandingCompletionSource with + member __.GetExpandedCompletionContextAsync(session, expander, initialTrigger, applicableToSpan, token) = + let ctx = Data.CompletionContext.Empty + Task.FromResult ctx + + + interface IAsyncCompletionSource with + member this.GetCompletionContextAsync(session, trigger, triggerLocation, applicableToSpan, token) = + async { + System.Diagnostics.Trace.WriteLine("GetCompletionContextAsync") + let document = session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() + let! sourceText = document.GetTextAsync() |> Async.AwaitTask + let provider = FSharpCompletionProvider(document.Project.Solution.Workspace, checkerProvider, projectInfoManager, assemblyContentProvider) + //let! completions = provider.ProvideCompletionsAsync(session.) |> Async.AwaitTask + let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, token) + match options with + | Some (_parsingOptions, projectOptions) -> + let! textVersion = document.GetTextVersionAsync(token) |> liftTaskAsync + let getAllSymbols(fileCheckResults: FSharpCheckFileResults) = + if settings.IntelliSense.IncludeSymbolsFromUnopenedNamespacesOrModules + then assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies(fileCheckResults) + else [] + + + session.TextView.Properties.["PotentialCommitCharacters"] <- commitChars + //static member ProvideCompletionsAsyncAux(checker: FSharpChecker, sourceText: SourceText, caretPosition: int, options: FSharpProjectOptions, filePath: string, + //textVersionHash: int, getAllSymbols: FSharpCheckFileResults -> AssemblySymbol list, languageServicePerformanceOptions: LanguageServicePerformanceOptions, intellisenseOptions: IntelliSenseOptions) = + let! completions = FSharpCompletionProvider.ProvideCompletionsAsyncAux(this, checkerProvider.Checker, sourceText, triggerLocation.Position, projectOptions, document.FilePath, textVersion.GetHashCode(), getAllSymbols, settings.LanguageServicePerformance, settings.IntelliSense) + match completions with + | Some completions' -> + return new Data.CompletionContext(completions'.ToImmutableArray()) + | None -> + return Data.CompletionContext.Empty + | _ -> + return Data.CompletionContext.Empty + } |> RoslynHelpers.StartAsyncAsTask token + + /// + /// Called once per completion session to fetch the set of all completion items available at a given location. + /// Called on a background thread. + /// + /// Reference to the active + /// What caused the completion + /// Location where completion was triggered, on the subject buffer that matches this 's content type + /// Location where completion will take place, on the view's data buffer: + /// Cancellation token that may interrupt this operation + /// A struct that holds completion items and applicable span + //Task GetCompletionContextAsync( + //IAsyncCompletionSession session, + //CompletionTrigger trigger, + //SnapshotPoint triggerLocation, + //SnapshotSpan applicableToSpan, + //CancellationToken token); + + /// + /// Returns tooltip associated with provided . + /// The returned object will be rendered by . See its documentation for default supported types. + /// You may export a to provide a renderer for a custom type. + /// Since this method is called on a background thread and on multiple platforms, an instance of UIElement may not be returned. + /// + /// Reference to the active + /// which is a subject of the tooltip + /// Cancellation token that may interrupt this operation + /// An object that will be passed to . See its documentation for supported types. + //Task GetDescriptionAsync(IAsyncCompletionSession session, CompletionItem item, CancellationToken token); + member __.GetDescriptionAsync(session, item, token) = + System.Diagnostics.Trace.WriteLine("descriptions") + Task.FromResult ("Description" :> _) + + /// + /// Provides the span applicable to the prospective session. + /// Called on UI thread and expected to return very quickly, based on syntactic clues. + /// This method is called as a result of user action, after the Editor makes necessary changes in direct response to user's action. + /// The state of the Editor prior to making the text edit is captured in of . + /// This method is called sequentially on available s until one of them returns + /// with appropriate level of + /// and one returns with + /// If neither of the above conditions are met, no completion session will start. + /// + /// + /// If a language service does not wish to participate in completion, it should try to provide a valid + /// and set to false. + /// This will enable other extensions to provide completion in syntactically appropriate location. + /// + /// What causes the completion, including the character typed and reference to prior to triggering the completion + /// Location on the subject buffer that matches this 's content type + /// Cancellation token that may interrupt this operation + /// Whether this wishes to participate in completion. + //CompletionStartData InitializeCompletion(CompletionTrigger trigger, SnapshotPoint triggerLocation, CancellationToken token); + member __.InitializeCompletion(trigger, triggerLocation, token) = + System.Diagnostics.Trace.WriteLine("initialize") + //Data.CompletionStartData.DoesNotParticipateInCompletion + //Data.CompletionStartData.ParticipatesInCompletionIfAny + + let document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); + if document = null then + Data.CompletionStartData.DoesNotParticipateInCompletion; + else + let sourceText = document.GetTextAsync(token).Result // GetTextSynchronously(token); + + Data.CompletionStartData( + participation = Data.CompletionParticipation.ProvidesItems, + applicableToSpan = new SnapshotSpan( + triggerLocation.Snapshot, + CompletionUtils.getCompletionItemSpan sourceText triggerLocation.Position)) + + + + +[)>] +[)>] +[] +[] +type internal CompletionSourceProvider + [] + ( + checkerProvider: FSharpCheckerProvider, + projectInfoManager: FSharpProjectOptionsManager, + assemblyContentProvider: AssemblyContentProvider + ) = + + interface IAsyncCompletionSourceProvider with + member __.GetOrCreate(textView) = + System.Diagnostics.Trace.WriteLine("Completion .ctor") + new FSharpCompletionSource(textView, checkerProvider, projectInfoManager, assemblyContentProvider) :> _ + + interface IAsyncCompletionCommitManagerProvider with + member __.GetOrCreate(textView) = + System.Diagnostics.Trace.WriteLine("GetOrCreate FSharpAsyncCompletionCommitManager") + FSharpAsyncCompletionCommitManager() :> _ + +open System.Composition +open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion +open Microsoft.VisualStudio.Utilities +open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.Text.Editor +[)>] +[] +[] +//[] +//[] +type internal FSharpAsyncCompletionCommitManagerProvider + [] + ( + checkerProvider: FSharpCheckerProvider + ) = + let x = 1 + interface IAsyncCompletionCommitManagerProvider with + member __.GetOrCreate(textView) = + System.Diagnostics.Trace.WriteLine("GetOrCreate FSharpAsyncCompletionCommitManager") + FSharpAsyncCompletionCommitManager() :> _ diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs index 5d210d5f363..34655d81048 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs @@ -11,7 +11,7 @@ open Microsoft.CodeAnalysis.Completion open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion open System.Globalization open FSharp.Compiler.SourceCodeServices - +open Microsoft.VisualStudio.Text module internal CompletionUtils = let private isLetterChar (cat: UnicodeCategory) = @@ -110,4 +110,63 @@ module internal CompletionUtils = | CompletionItemKind.Event -> 4 | CompletionItemKind.Argument -> 5 | CompletionItemKind.Other -> 6 - | CompletionItemKind.Method (isExtension = true) -> 7 \ No newline at end of file + | CompletionItemKind.Method (isExtension = true) -> 7 + + + //public static TextSpan GetWordSpan(SourceText text, int position, + // Func isWordStartCharacter, Func isWordCharacter, bool alwaysExtendEndSpan = false) + //{ + // var start = position; + // while (start > 0 && isWordStartCharacter(text[start - 1])) + // { + // start--; + // } + + // // If we're brought up in the middle of a word, extend to the end of the word as well. + // // This means that if a user brings up the completion list at the start of the word they + // // will "insert" the text before what's already there (useful for qualifying existing + // // text). However, if they bring up completion in the "middle" of a word, then they will + // // "overwrite" the text. Useful for correcting misspellings or just replacing unwanted + // // code with new code. + // var end = position; + // if (start != position || alwaysExtendEndSpan) + // { + // while (end < text.Length && isWordCharacter(text[end])) + // { + // end++; + // } + // } + + // return TextSpan.FromBounds(start, end); + //} + + let getCompletionItemSpan (sourceText: SourceText) position = + let rec findStart index = + let c = sourceText.[index-1] + match isIdentifierStartCharacter c with + | true when index > 0 -> + findStart (index-1) + | _ -> index + + // If we're brought up in the middle of a word, extend to the end of the word as well. + // This means that if a user brings up the completion list at the start of the word they + // will "insert" the text before what's already there (useful for qualifying existing + // text). However, if they bring up completion in the "middle" of a word, then they will + // "overwrite" the text. Useful for correcting misspellings or just replacing unwanted + // code with new code. + let rec findEnd index = + let c = sourceText.[index] + match isIdentifierStartCharacter c with + | true when index < sourceText.Length -> + findEnd (index+1) + | _ -> index + + let start = findStart position + + let endIndex = + if start <> position then + findEnd position + else + position + + Span.FromBounds(start, endIndex) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.Designer.fs b/vsintegration/src/FSharp.Editor/FSharp.Editor.Designer.fs index 31d1c209e8b..18eedbf7541 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.Designer.fs +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.Designer.fs @@ -14,7 +14,7 @@ type FSharp_Editor() = [] static val mutable private resourceCulture:System.Globalization.CultureInfo [] - static member ResourceManager + member this.ResourceManager with get() : System.Resources.ResourceManager = if System.Object.Equals((Unchecked.defaultof<_>), FSharp_Editor.resourceMan) then let mutable (temp:System.Resources.ResourceManager) = new System.Resources.ResourceManager("FSharp.Editor.resx", (typeof).Assembly) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index e12365fae2e..e53d39976cb 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -20,9 +20,13 @@ false + portable false ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor + 3 + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor\FSharp.Editor.XML false + --warnon:11111182 --subsystemversion:6.00 --simpleresolution --nocopyfsharpcore ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor @@ -48,10 +52,10 @@ - + - + @@ -120,8 +124,10 @@ + + @@ -147,15 +153,9 @@ - + FSharp.Editor.resx - - - true - Microsoft.VisualStudio.FSharp.Editor.SR - PublicResXFileCodeGenerator - FSharp.Editor.Designer.fs - + @@ -165,43 +165,49 @@ - - + + true + Microsoft.VisualStudio.FSharp.Editor.SR + PublicResXFileCodeGenerator + FSharp.Editor.Designer.fs + - - - - - - - - - - - - - - - - - - Common\LspExternalAccess.fs - - - - - - - + + + + Common\LspExternalAccess.fs + + + + + + + - - + + + + + + + + + + + + + - + + + + + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs b/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs index ab92c7a72ee..0eaf862dcb8 100644 --- a/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs +++ b/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs @@ -135,7 +135,6 @@ type EditorOptions [] module internal WorkspaceSettingFromDocumentExtension = - let options = EditorOptions() type Microsoft.CodeAnalysis.Document with - member this.FSharpOptions = options - //this.Project.Solution.Workspace.Services.GetService() : EditorOptions + member this.FSharpOptions = + this.Project.Solution.Workspace.Services.GetService() : EditorOptions diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index 83dbab3a68b..5c6458a507d 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -280,9 +280,9 @@ type internal FSharpAsyncQuickInfoSourceProvider ) = interface IAsyncQuickInfoSourceProvider with - override __.TryCreateQuickInfoSource(textBuffer:ITextBuffer) : IAsyncQuickInfoSource = + override __.TryCreateQuickInfoSource(textBuffer) = // GetService calls must be made on the UI thread // It is safe to do it here (see #4713) let statusBar = StatusBar((*serviceProvider.GetService()*)) //let xmlMemberIndexService = serviceProvider.XMLMemberIndexService - new FSharpAsyncQuickInfoSource(statusBar, (* xmlMemberIndexService,*) checkerProvider, projectInfoManager, textBuffer, settings) :> IAsyncQuickInfoSource + new FSharpAsyncQuickInfoSource(statusBar, (* xmlMemberIndexService,*) checkerProvider, projectInfoManager, textBuffer, settings) :> _ From 1415e5e16cef2ca03b240cc5647587cf863822d2 Mon Sep 17 00:00:00 2001 From: nosami Date: Sun, 5 Jan 2020 13:34:34 +0000 Subject: [PATCH 008/101] glyphs --- .../Completion/CompletionProvider.fs | 27 ++- .../FSharp.Editor/Completion/GlyphHelper.fs | 208 ++++++++++++++++++ .../src/FSharp.Editor/FSharp.Editor.fsproj | 27 +-- 3 files changed, 241 insertions(+), 21 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/Completion/GlyphHelper.fs diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index bd78f7a614d..e9b63db09fb 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -20,7 +20,7 @@ open FSharp.Compiler open FSharp.Compiler.Range open FSharp.Compiler.SourceCodeServices open Microsoft.VisualStudio.Text.Adornments - +open Microsoft.CodeAnalysis.Editor.Shared.Extensions module Logger = Microsoft.VisualStudio.FSharp.Editor.Logger type internal FSharpCompletionProvider @@ -137,6 +137,7 @@ type internal FSharpCompletionProvider declarationItems |> Array.iteri (fun number declarationItem -> let glyph = Tokenizer.FSharpGlyphToRoslynGlyph (declarationItem.Glyph, declarationItem.Accessibility) + let image = GlyphHelper.getImageId glyph |> ImageElement let name = match declarationItem.NamespaceToOpen with | Some namespaceToOpen -> sprintf "%s (open %s)" declarationItem.Name namespaceToOpen @@ -151,7 +152,7 @@ type internal FSharpCompletionProvider | _, idents -> Array.last idents let completionItem = - new Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem(name, completionSource) + new Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem(name, completionSource, icon = image) //FSharpCommonCompletionItem.Create(name, null, rules = getRules intellisenseOptions.ShowAfterCharIsTyped, glyph = Nullable glyph, filterText = filterText) //.AddProperty(FullNamePropName, declarationItem.FullName) @@ -190,17 +191,27 @@ type internal FSharpCompletionProvider |> Option.bind (fun parseTree -> UntypedParseImpl.TryGetCompletionContext(Pos.fromZ caretLinePos.Line caretLinePos.Character, parseTree, lineStr)) - let keywordGlyph = ExternalAccess.FSharp.FSharpGlyph.Keyword + //let keywordGlyph = ExternalAccess.FSharp.FSharpGlyph.Keyword + //let k = Glyph.Keyword + //let roslynGlyph = Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.FSharpGlyphHelpers.ConvertTo(k) + //let i = ImageElement(roslynGlyph |> Gl GetImageId) + let image = GlyphHelper.getImageId Glyph.Keyword |> ImageElement + //let c = + //FSharpCommonCompletionItem.Create(keyword, null, CompletionItemRules.Default, Nullable Glyph.Keyword ) + //.AddProperty("description", description) + //.AddProperty(IsKeywordPropName, "") match completionContext with | None -> let keywordItemsWithSource = keywordCompletionItems - |> List.mapi (fun n (keyword, description) -> + |> Seq.mapi (fun n (keyword, description) -> + //FSharpCommonCompletionItem.Create(keyword, null, CompletionItemRules.Default, Nullable Glyph.Keyword ) + //.AddProperty("description", description) + //.AddProperty(IsKeywordPropName, "")) + let imageId = [ ] new Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem - (keyword, completionSource, null, ImmutableArray.Empty, "", keyword, sprintf "%06d" (1000000 + n), keyword, keyword, ImmutableArray.Empty )) - //FSharpCommonCompletionItem.Create(keyword, null, CompletionItemRules.Default, Nullable Glyph.Keyword, )) - //.AddProperty("description", description) - //.AddProperty(IsKeywordPropName, "")) + (keyword, completionSource, image, ImmutableArray.Empty, "", keyword, sprintf "%06d" (1000000 + n), keyword, keyword, ImmutableArray.Empty )) + results.AddRange(keywordItemsWithSource) | _ -> () diff --git a/vsintegration/src/FSharp.Editor/Completion/GlyphHelper.fs b/vsintegration/src/FSharp.Editor/Completion/GlyphHelper.fs new file mode 100644 index 00000000000..d4beb5f4f95 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Completion/GlyphHelper.fs @@ -0,0 +1,208 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.VisualStudio.FSharp.Editor +open System +open Microsoft.CodeAnalysis.Tags; +open Microsoft.VisualStudio.Core.Imaging; +open Microsoft.VisualStudio.Imaging; +module GlyphHelper = + // hardcode imageCatalogGuid locally rather than calling KnownImageIds.imageCatalogGuid + // So it doesnot have dependency for Microsoft.VisualStudio.ImageCatalog.dll + // https://github.com/dotnet/roslyn/issues/26642 + let imageCatalogGuid = Guid.Parse("ae27a6b0-e345-4288-96df-5eaf394ee369"); + + let getImageId (glyph:Glyph) = + // VS for mac cannot refer to ImageMoniker + // so we need to expose ImageId instead of ImageMoniker here + // and expose ImageMoniker in the EditorFeatures.wpf.dll + match glyph with + | Glyph.None -> + new ImageId(imageCatalogGuid, KnownImageIds.None) + + | Glyph.Assembly -> + new ImageId(imageCatalogGuid, KnownImageIds.Assembly) + + | Glyph.BasicFile -> + new ImageId(imageCatalogGuid, KnownImageIds.VBFileNode) + | Glyph.BasicProject -> + new ImageId(imageCatalogGuid, KnownImageIds.VBProjectNode) + + | Glyph.ClassPublic -> + new ImageId(imageCatalogGuid, KnownImageIds.ClassPublic) + | Glyph.ClassProtected -> + new ImageId(imageCatalogGuid, KnownImageIds.ClassProtected) + | Glyph.ClassPrivate -> + new ImageId(imageCatalogGuid, KnownImageIds.ClassPrivate) + | Glyph.ClassInternal -> + new ImageId(imageCatalogGuid, KnownImageIds.ClassInternal) + + | Glyph.CSharpFile -> + new ImageId(imageCatalogGuid, KnownImageIds.CSFileNode) + | Glyph.CSharpProject -> + new ImageId(imageCatalogGuid, KnownImageIds.CSProjectNode) + + | Glyph.ConstantPublic -> + new ImageId(imageCatalogGuid, KnownImageIds.ConstantPublic) + | Glyph.ConstantProtected -> + new ImageId(imageCatalogGuid, KnownImageIds.ConstantProtected) + | Glyph.ConstantPrivate -> + new ImageId(imageCatalogGuid, KnownImageIds.ConstantPrivate) + | Glyph.ConstantInternal -> + new ImageId(imageCatalogGuid, KnownImageIds.ConstantInternal) + + | Glyph.DelegatePublic -> + new ImageId(imageCatalogGuid, KnownImageIds.DelegatePublic) + | Glyph.DelegateProtected -> + new ImageId(imageCatalogGuid, KnownImageIds.DelegateProtected) + | Glyph.DelegatePrivate -> + new ImageId(imageCatalogGuid, KnownImageIds.DelegatePrivate) + | Glyph.DelegateInternal -> + new ImageId(imageCatalogGuid, KnownImageIds.DelegateInternal) + + | Glyph.EnumPublic -> + new ImageId(imageCatalogGuid, KnownImageIds.EnumerationPublic) + | Glyph.EnumProtected -> + new ImageId(imageCatalogGuid, KnownImageIds.EnumerationProtected) + | Glyph.EnumPrivate -> + new ImageId(imageCatalogGuid, KnownImageIds.EnumerationPrivate) + | Glyph.EnumInternal -> + new ImageId(imageCatalogGuid, KnownImageIds.EnumerationInternal) + + | Glyph.EnumMemberPublic + | Glyph.EnumMemberProtected + | Glyph.EnumMemberPrivate + | Glyph.EnumMemberInternal -> + new ImageId(imageCatalogGuid, KnownImageIds.EnumerationItemPublic) + + | Glyph.Error -> + new ImageId(imageCatalogGuid, KnownImageIds.StatusError) + + | Glyph.EventPublic -> + new ImageId(imageCatalogGuid, KnownImageIds.EventPublic) + | Glyph.EventProtected -> + new ImageId(imageCatalogGuid, KnownImageIds.EventProtected) + | Glyph.EventPrivate -> + new ImageId(imageCatalogGuid, KnownImageIds.EventPrivate) + | Glyph.EventInternal -> + new ImageId(imageCatalogGuid, KnownImageIds.EventInternal) + + // Extension methods have the same glyph regardless of accessibility. + | Glyph.ExtensionMethodPublic + | Glyph.ExtensionMethodProtected + | Glyph.ExtensionMethodPrivate + | Glyph.ExtensionMethodInternal -> + new ImageId(imageCatalogGuid, KnownImageIds.ExtensionMethod); + + | Glyph.FieldPublic -> + new ImageId(imageCatalogGuid, KnownImageIds.FieldPublic) + | Glyph.FieldProtected -> + new ImageId(imageCatalogGuid, KnownImageIds.FieldProtected) + | Glyph.FieldPrivate -> + new ImageId(imageCatalogGuid, KnownImageIds.FieldPrivate) + | Glyph.FieldInternal -> + new ImageId(imageCatalogGuid, KnownImageIds.FieldInternal) + + | Glyph.InterfacePublic -> + new ImageId(imageCatalogGuid, KnownImageIds.InterfacePublic) + | Glyph.InterfaceProtected -> + new ImageId(imageCatalogGuid, KnownImageIds.InterfaceProtected) + | Glyph.InterfacePrivate -> + new ImageId(imageCatalogGuid, KnownImageIds.InterfacePrivate) + | Glyph.InterfaceInternal -> + new ImageId(imageCatalogGuid, KnownImageIds.InterfaceInternal) + + // TODO: Figure out the right thing to return here. + | Glyph.Intrinsic -> + new ImageId(imageCatalogGuid, KnownImageIds.Type) + + | Glyph.Keyword -> + new ImageId(imageCatalogGuid, KnownImageIds.IntellisenseKeyword) + + | Glyph.Label -> + new ImageId(imageCatalogGuid, KnownImageIds.Label) + + | Glyph.Parameter + | Glyph.Local -> + new ImageId(imageCatalogGuid, KnownImageIds.LocalVariable); + + | Glyph.Namespace -> + new ImageId(imageCatalogGuid, KnownImageIds.Namespace) + + | Glyph.MethodPublic -> + new ImageId(imageCatalogGuid, KnownImageIds.MethodPublic) + | Glyph.MethodProtected -> + new ImageId(imageCatalogGuid, KnownImageIds.MethodProtected) + | Glyph.MethodPrivate -> + new ImageId(imageCatalogGuid, KnownImageIds.MethodPrivate) + | Glyph.MethodInternal -> + new ImageId(imageCatalogGuid, KnownImageIds.MethodInternal) + + | Glyph.ModulePublic -> + new ImageId(imageCatalogGuid, KnownImageIds.ModulePublic) + | Glyph.ModuleProtected -> + new ImageId(imageCatalogGuid, KnownImageIds.ModuleProtected) + | Glyph.ModulePrivate -> + new ImageId(imageCatalogGuid, KnownImageIds.ModulePrivate) + | Glyph.ModuleInternal -> + new ImageId(imageCatalogGuid, KnownImageIds.ModuleInternal) + + | Glyph.OpenFolder -> + new ImageId(imageCatalogGuid, KnownImageIds.OpenFolder) + + | Glyph.Operator -> + new ImageId(imageCatalogGuid, KnownImageIds.Operator) + + | Glyph.PropertyPublic -> + new ImageId(imageCatalogGuid, KnownImageIds.PropertyPublic) + | Glyph.PropertyProtected -> + new ImageId(imageCatalogGuid, KnownImageIds.PropertyProtected) + | Glyph.PropertyPrivate -> + new ImageId(imageCatalogGuid, KnownImageIds.PropertyPrivate) + | Glyph.PropertyInternal -> + new ImageId(imageCatalogGuid, KnownImageIds.PropertyInternal) + + | Glyph.RangeVariable -> + new ImageId(imageCatalogGuid, KnownImageIds.FieldPublic) + + | Glyph.Reference -> + new ImageId(imageCatalogGuid, KnownImageIds.Reference) + + //// this is not a copy-paste mistake, we were using these before in the previous GetImageMoniker() + //| Glyph.StructurePublic -> + // return KnownMonikers.ValueTypePublic + //| Glyph.StructureProtected -> + // return KnownMonikers.ValueTypeProtected + //| Glyph.StructurePrivate -> + // return KnownMonikers.ValueTypePrivate + //| Glyph.StructureInternal -> + // return KnownMonikers.ValueTypeInternal + + | Glyph.StructurePublic -> + new ImageId(imageCatalogGuid, KnownImageIds.ValueTypePublic) + | Glyph.StructureProtected -> + new ImageId(imageCatalogGuid, KnownImageIds.ValueTypeProtected) + | Glyph.StructurePrivate -> + new ImageId(imageCatalogGuid, KnownImageIds.ValueTypePrivate) + | Glyph.StructureInternal -> + new ImageId(imageCatalogGuid, KnownImageIds.ValueTypeInternal) + + | Glyph.TypeParameter -> + new ImageId(imageCatalogGuid, KnownImageIds.Type) + + | Glyph.Snippet -> + new ImageId(imageCatalogGuid, KnownImageIds.Snippet) + + | Glyph.CompletionWarning -> + new ImageId(imageCatalogGuid, KnownImageIds.IntellisenseWarning) + + | Glyph.StatusInformation -> + new ImageId(imageCatalogGuid, KnownImageIds.StatusInformation) + + | Glyph.NuGet -> + new ImageId(imageCatalogGuid, KnownImageIds.NuGet) + + //| Glyph.TargetTypeMatch -> + //new ImageId(imageCatalogGuid, KnownImageIds.MatchType) + + | _ -> + raise(new ArgumentException("glyph")) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index e53d39976cb..4c1d90bd375 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -120,6 +120,7 @@ + @@ -171,43 +172,43 @@ PublicResXFileCodeGenerator FSharp.Editor.Designer.fs - - - - + - + + + Common\LspExternalAccess.fs - + + + + - - - + - - - + + + - + \ No newline at end of file From db863c3f3deacec4938fb7d887f2a1632a12b992 Mon Sep 17 00:00:00 2001 From: nosami Date: Sun, 5 Jan 2020 22:36:18 +0000 Subject: [PATCH 009/101] classified intellisense descriptions --- .../Completion/CompletionProvider.fs | 37 +++- .../Completion/CompletionService.fs | 171 +++++++++++++++++- .../FSharp.Editor/Completion/GlyphHelper.fs | 4 +- .../LanguageService/LanguageService.fs | 2 +- 4 files changed, 202 insertions(+), 12 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index e9b63db09fb..52a003747ec 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -20,6 +20,8 @@ open FSharp.Compiler open FSharp.Compiler.Range open FSharp.Compiler.SourceCodeServices open Microsoft.VisualStudio.Text.Adornments +open Microsoft.VisualStudio.Text +open Microsoft.VisualStudio.Text.Editor open Microsoft.CodeAnalysis.Editor.Shared.Extensions module Logger = Microsoft.VisualStudio.FSharp.Editor.Logger @@ -56,7 +58,7 @@ type internal FSharpCompletionProvider let settings: EditorOptions = workspace.Services.GetService() //let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder(serviceProvider.XMLMemberIndexService) - + let documentationBuilder = XmlDocumentation.Provider() static let noCommitOnSpaceRules = // These are important. They make sure we don't _commit_ autocompletion when people don't expect them to. Some examples: // @@ -152,10 +154,12 @@ type internal FSharpCompletionProvider | _, idents -> Array.last idents let completionItem = - new Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem(name, completionSource, icon = image) + let item = new Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem(name, completionSource, icon = image) //FSharpCommonCompletionItem.Create(name, null, rules = getRules intellisenseOptions.ShowAfterCharIsTyped, glyph = Nullable glyph, filterText = filterText) //.AddProperty(FullNamePropName, declarationItem.FullName) - + item.Properties.AddProperty(IndexPropName, declarationItem) + item + let completionItem = match declarationItem.Kind with | CompletionItemKind.Method (isExtension = true) -> @@ -257,12 +261,12 @@ type internal FSharpCompletionProvider | true, completionItemIndexStr -> let completionItemIndex = int completionItemIndexStr if completionItemIndex < declarationItems.Length then - //let declarationItem = declarationItems.[completionItemIndex] - //let! description = declarationItem.StructuredDescriptionTextAsync + let declarationItem = declarationItems.[completionItemIndex] + let! description = declarationItem.StructuredDescriptionTextAsync let documentation = List() - //let collector = RoslynHelpers.CollectTaggedText documentation + let collector = RoslynHelpers.CollectTaggedText documentation // mix main description and xmldoc by using one collector - //XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, collector, collector, collector, description) + XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, collector, collector, collector, description) return CompletionDescription.Create(documentation.ToImmutableArray()) else return CompletionDescription.Empty @@ -270,6 +274,25 @@ type internal FSharpCompletionProvider return CompletionDescription.Empty } |> RoslynHelpers.StartAsyncAsTask cancellationToken + member this.GetDescriptionAsync2(textView: ITextView, completionItem: Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem, cancellationToken: CancellationToken): Task = + async { + //use _logBlock = Logger.LogBlockMessage "DocumentName" ViewportWidthLogEditorFunctionId.Completion_GetDescriptionAsync + match completionItem.Properties.TryGetProperty IndexPropName with + | true, (declarationItem: FSharpDeclarationListItem) -> + //let completionItemIndex = int completionItemIndexStr + //if completionItemIndex < declarationItems.Length then + //let declarationItem = declarationItems.[completionItemIndex] + let! description = declarationItem.StructuredDescriptionTextAsync + let documentation = List() + let collector = RoslynHelpers.CollectTaggedText documentation + // mix main description and xmldoc by using one collector + XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, collector, collector, collector, description) + return CompletionDescription.Create(documentation.ToImmutableArray()) + //else + //return CompletionDescription.Empty + | _ -> + return CompletionDescription.Empty + } |> RoslynHelpers.StartAsyncAsTask cancellationToken override this.GetChangeAsync(document, item, _, cancellationToken) : Task = async { use _logBlock = Logger.LogBlockMessage document.Name LogEditorFunctionId.Completion_GetChangeAsync diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index 59f90e7068a..f75faa61766 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -33,6 +33,7 @@ open System.Linq; open System.Runtime.CompilerServices; open System.Threading; open System.Threading.Tasks; +open Microsoft.CodeAnalysis.Classification open Microsoft.CodeAnalysis.Completion; open Microsoft.CodeAnalysis.Completion.Providers; open Microsoft.CodeAnalysis.Editor.Host; @@ -53,6 +54,29 @@ open Microsoft.VisualStudio.Text.Adornments; open FSharp.Compiler open FSharp.Compiler.Range open FSharp.Compiler.SourceCodeServices + +open System.Collections.Generic; +open System.Collections.Immutable; +open System.Linq; +open System.Runtime.CompilerServices; +open System.Threading; +open System.Threading.Tasks; +open Microsoft.CodeAnalysis.Completion; +open Microsoft.CodeAnalysis.Completion.Providers; +open Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion; +open Microsoft.CodeAnalysis.Editor.Shared.Extensions; +open Microsoft.CodeAnalysis.Editor.Shared.Utilities; +open Microsoft.CodeAnalysis.Experiments; +open Microsoft.CodeAnalysis.LanguageServices; +open Microsoft.CodeAnalysis.PooledObjects; +open Microsoft.CodeAnalysis.Shared.Extensions; +open Microsoft.CodeAnalysis.Text; +open Microsoft.CodeAnalysis.Text.Shared.Extensions; +open Microsoft.VisualStudio.Core.Imaging; +open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; +open Microsoft.VisualStudio.Text; +open Microsoft.VisualStudio.Text.Adornments; +open Microsoft.VisualStudio.Text.Editor; //open Microsoft.VisualStudio.Text.Editor; //open AsyncCompletionData = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; //open RoslynCompletionItem = Microsoft.CodeAnalysis.Completion.CompletionItem; @@ -135,6 +159,143 @@ type internal FSharpCompletionSource let settings: EditorOptions = textView.TextBuffer.GetWorkspace().Services.GetService() + let createParagraphFromLines(lines: List) = + if lines.Count = 1 then + // The paragraph contains only one line, so it doesn't need to be added to a container. Avoiding the + // wrapping container here also avoids a wrapping element in the WPF elements used for rendering, + // improving efficiency. + lines.[0] :> obj + else + // The lines of a multi-line paragraph are stacked to produce the full paragraph. + ContainerElement(ContainerElementStyle.Stacked, lines) :> obj + + let toClassificationTypeName = function + | TextTags.Keyword -> + ClassificationTypeNames.Keyword + + | TextTags.Class -> + ClassificationTypeNames.ClassName + + | TextTags.Delegate -> + ClassificationTypeNames.DelegateName + + | TextTags.Enum -> + ClassificationTypeNames.EnumName + + | TextTags.Interface -> + ClassificationTypeNames.InterfaceName + + | TextTags.Module -> + ClassificationTypeNames.ModuleName + + | TextTags.Struct -> + ClassificationTypeNames.StructName + + | TextTags.TypeParameter -> + ClassificationTypeNames.TypeParameterName + + | TextTags.Field -> + ClassificationTypeNames.FieldName + + | TextTags.Event -> + ClassificationTypeNames.EventName + + | TextTags.Label -> + ClassificationTypeNames.LabelName + + | TextTags.Local -> + ClassificationTypeNames.LocalName + + | TextTags.Method -> + ClassificationTypeNames.MethodName + + | TextTags.Namespace -> + ClassificationTypeNames.NamespaceName + + | TextTags.Parameter -> + ClassificationTypeNames.ParameterName + + | TextTags.Property -> + ClassificationTypeNames.PropertyName + + | TextTags.ExtensionMethod -> + ClassificationTypeNames.ExtensionMethodName + + | TextTags.EnumMember -> + ClassificationTypeNames.EnumMemberName + + | TextTags.Constant -> + ClassificationTypeNames.ConstantName + + | TextTags.Alias + | TextTags.Assembly + | TextTags.ErrorType + | TextTags.RangeVariable -> + ClassificationTypeNames.Identifier + + | TextTags.NumericLiteral -> + ClassificationTypeNames.NumericLiteral + + | TextTags.StringLiteral -> + ClassificationTypeNames.StringLiteral + + | TextTags.Space + | TextTags.LineBreak -> + ClassificationTypeNames.WhiteSpace + + | TextTags.Operator -> + ClassificationTypeNames.Operator + + | TextTags.Punctuation -> + ClassificationTypeNames.Punctuation + + | TextTags.AnonymousTypeIndicator + | TextTags.Text + | _ -> + ClassificationTypeNames.Text + + + let buildClassifiedTextElements (taggedTexts:ImmutableArray) = + // This method produces a sequence of zero or more paragraphs + let paragraphs = new List() + + // Each paragraph is constructed from one or more lines + let currentParagraph = new List() + + // Each line is constructed from one or more inline elements + let currentRuns = new List() + + for part in taggedTexts do + if part.Tag = TextTags.LineBreak then + if currentRuns.Count > 0 then + // This line break means the end of a line within a paragraph. + currentParagraph.Add(new ClassifiedTextElement(currentRuns)); + currentRuns.Clear(); + else + // This line break means the end of a paragraph. Empty paragraphs are ignored, but could appear + // in the input to this method: + // + // * Empty elements + // * Explicit line breaks at the start of a comment + // * Multiple line breaks between paragraphs + if currentParagraph.Count > 0 then + // The current paragraph is not empty, so add it to the result collection + paragraphs.Add(createParagraphFromLines(currentParagraph)) + currentParagraph.Clear(); + + else + // This is tagged text getting added to the current line we are building. + currentRuns.Add(new ClassifiedTextRun(part.Tag |> toClassificationTypeName, part.Text)) + + if currentRuns.Count > 0 then + // Add the final line to the final paragraph. + currentParagraph.Add(new ClassifiedTextElement(currentRuns)) + + if currentParagraph.Count > 0 then + // Add the final paragraph to the result. + paragraphs.Add(createParagraphFromLines(currentParagraph)) + + paragraphs /// /// Called when user interacts with expander buttons, /// requesting the completion source to provide additional completion items pertinent to the expander button. @@ -220,8 +381,14 @@ type internal FSharpCompletionSource /// An object that will be passed to . See its documentation for supported types. //Task GetDescriptionAsync(IAsyncCompletionSession session, CompletionItem item, CancellationToken token); member __.GetDescriptionAsync(session, item, token) = - System.Diagnostics.Trace.WriteLine("descriptions") - Task.FromResult ("Description" :> _) + async { + let document = session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() + let! sourceText = document.GetTextAsync() |> Async.AwaitTask + let provider = FSharpCompletionProvider(document.Project.Solution.Workspace, checkerProvider, projectInfoManager, assemblyContentProvider) + let! description = provider.GetDescriptionAsync2(session.TextView, item, token) |> Async.AwaitTask + let elements = description.TaggedParts |> buildClassifiedTextElements + return ContainerElement(ContainerElementStyle.Stacked ||| ContainerElementStyle.VerticalPadding, elements) :> obj + } |> RoslynHelpers.StartAsyncAsTask token /// /// Provides the span applicable to the prospective session. diff --git a/vsintegration/src/FSharp.Editor/Completion/GlyphHelper.fs b/vsintegration/src/FSharp.Editor/Completion/GlyphHelper.fs index d4beb5f4f95..5ba2738afb4 100644 --- a/vsintegration/src/FSharp.Editor/Completion/GlyphHelper.fs +++ b/vsintegration/src/FSharp.Editor/Completion/GlyphHelper.fs @@ -6,8 +6,8 @@ open Microsoft.CodeAnalysis.Tags; open Microsoft.VisualStudio.Core.Imaging; open Microsoft.VisualStudio.Imaging; module GlyphHelper = - // hardcode imageCatalogGuid locally rather than calling KnownImageIds.imageCatalogGuid - // So it doesnot have dependency for Microsoft.VisualStudio.ImageCatalog.dll + // hardcode imageCatalogGuid locally rather than calling KnownImageIds.ImageCatalogGuid + // So it does not have dependency on Microsoft.VisualStudio.ImageCatalog.dll // https://github.com/dotnet/roslyn/issues/26642 let imageCatalogGuid = Guid.Parse("ae27a6b0-e345-4288-96df-5eaf394ee369"); diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 6ecba291ba7..0daccb02607 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -114,7 +114,7 @@ type internal FSharpSettingsFactory ////[, "F#", null, "Formatting", "6014")>] ////[] ////// 64 represents a hex number. It needs to be greater than 37 so the TextMate editor will not be chosen as higher priority. -////[, ".fs", 64)>] +//[, ".fs", 64)>] ////[, ".fsi", 64)>] ////[, ".fsscript", 64)>] ////[, ".fsx", 64)>] From 6385303ff0d525aa604e02653ed3d3116a84bc55 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 6 Jan 2020 16:35:04 +0000 Subject: [PATCH 010/101] XML docs in tooltips --- .../Completion/CompletionService.fs | 33 ++--- .../DocComments/XMLDocumentation.fs | 119 +++++++++++++++++- 2 files changed, 130 insertions(+), 22 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index f75faa61766..5fe16ae612c 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -162,12 +162,12 @@ type internal FSharpCompletionSource let createParagraphFromLines(lines: List) = if lines.Count = 1 then // The paragraph contains only one line, so it doesn't need to be added to a container. Avoiding the - // wrapping container here also avoids a wrapping element in the WPF elements used for rendering, + // wrapping container here also avoids a wrapping element in the Cocoa elements used for rendering, // improving efficiency. lines.[0] :> obj else // The lines of a multi-line paragraph are stacked to produce the full paragraph. - ContainerElement(ContainerElementStyle.Stacked, lines) :> obj + ContainerElement(ContainerElementStyle.Stacked, lines |> Seq.map box) :> obj let toClassificationTypeName = function | TextTags.Keyword -> @@ -326,7 +326,8 @@ type internal FSharpCompletionSource async { System.Diagnostics.Trace.WriteLine("GetCompletionContextAsync") let document = session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() - let! sourceText = document.GetTextAsync() |> Async.AwaitTask + + let sourceText = session.TextView.TextSnapshot.AsText() let provider = FSharpCompletionProvider(document.Project.Solution.Workspace, checkerProvider, projectInfoManager, assemblyContentProvider) //let! completions = provider.ProvideCompletionsAsync(session.) |> Async.AwaitTask let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, token) @@ -386,8 +387,9 @@ type internal FSharpCompletionSource let! sourceText = document.GetTextAsync() |> Async.AwaitTask let provider = FSharpCompletionProvider(document.Project.Solution.Workspace, checkerProvider, projectInfoManager, assemblyContentProvider) let! description = provider.GetDescriptionAsync2(session.TextView, item, token) |> Async.AwaitTask - let elements = description.TaggedParts |> buildClassifiedTextElements - return ContainerElement(ContainerElementStyle.Stacked ||| ContainerElementStyle.VerticalPadding, elements) :> obj + let elements = description.TaggedParts |> buildClassifiedTextElements + return ContainerElement(ContainerElementStyle.Stacked ||| ContainerElementStyle.VerticalPadding, elements |> Seq.map box) :> obj + //return elements :> obj } |> RoslynHelpers.StartAsyncAsTask token /// @@ -417,18 +419,17 @@ type internal FSharpCompletionSource let document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); if document = null then - - Data.CompletionStartData.DoesNotParticipateInCompletion; + Data.CompletionStartData.DoesNotParticipateInCompletion else - let sourceText = document.GetTextAsync(token).Result // GetTextSynchronously(token); - - Data.CompletionStartData( - participation = Data.CompletionParticipation.ProvidesItems, - applicableToSpan = new SnapshotSpan( - triggerLocation.Snapshot, - CompletionUtils.getCompletionItemSpan sourceText triggerLocation.Position)) - - + match document.TryGetText() with + | true, sourceText -> + Data.CompletionStartData( + participation = Data.CompletionParticipation.ProvidesItems, + applicableToSpan = new SnapshotSpan( + triggerLocation.Snapshot, + CompletionUtils.getCompletionItemSpan sourceText triggerLocation.Position)) + | false, _ -> + Data.CompletionStartData.DoesNotParticipateInCompletion [)>] diff --git a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs index 5a1ba0b6a51..c365cf8066c 100644 --- a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs +++ b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs @@ -11,6 +11,16 @@ open FSharp.Compiler.SourceCodeServices open FSharp.Compiler.Layout open FSharp.Compiler.Layout.TaggedTextOps open System.Collections.Generic +open System.IO +open System.Threading +open Microsoft.CodeAnalysis.Text; +open Microsoft.CodeAnalysis.Text.Shared.Extensions; +open Microsoft.VisualStudio.Core.Imaging; +open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; +open Microsoft.VisualStudio.Text; +open Microsoft.VisualStudio.Text.Adornments; +open Microsoft.VisualStudio.Text.Editor; +open System.Collections.Immutable type internal ITaggedTextCollector = abstract Add: text: TaggedText -> unit @@ -84,6 +94,83 @@ type internal IDocumentationBuilder = /// Documentation helpers. module internal XmlDocumentation = open System.Security + open System.Collections.Generic + open Internal.Utilities.StructuredFormat + open Microsoft.CodeAnalysis.Classification + open FSharp.Compiler + open Microsoft.VisualStudio.Core.Imaging + open Microsoft.VisualStudio.Language.StandardClassification + open Microsoft.VisualStudio.Text.Adornments + let layoutTagToClassificationTag (layoutTag:LayoutTag) = + match layoutTag with + | ActivePatternCase + | ActivePatternResult + | UnionCase + | Enum -> ClassificationTypeNames.EnumName // Roslyn-style classification name + | Alias + | Class + | Module + | Record + | Struct + | TypeParameter + | Union + | UnknownType -> PredefinedClassificationTypeNames.Type + | Interface -> ClassificationTypeNames.InterfaceName // Roslyn-style classification name + | Keyword -> PredefinedClassificationTypeNames.Keyword + | Delegate + | Event + | Field + | Local + | Member + | Method + | ModuleBinding + | Namespace + | Parameter + | Property + | RecordField -> PredefinedClassificationTypeNames.Identifier + | LineBreak + | Space -> PredefinedClassificationTypeNames.WhiteSpace + | NumericLiteral -> PredefinedClassificationTypeNames.Number + | Operator -> PredefinedClassificationTypeNames.Operator + | StringLiteral -> PredefinedClassificationTypeNames.String + | Punctuation + | Text + | UnknownEntity -> PredefinedClassificationTypeNames.Other + + let buildContainerElement (itemGroup:ImmutableArray) = + let finalCollection = List() + let currentContainerItems = List() + let runsCollection = List() + let flushRuns() = + if runsCollection.Count > 0 then + let element = ClassifiedTextElement(runsCollection) + currentContainerItems.Add(element :> obj) + runsCollection.Clear() + let flushContainer() = + if currentContainerItems.Count > 0 then + let element = ContainerElement(ContainerElementStyle.Wrapped, currentContainerItems) + finalCollection.Add(element) + currentContainerItems.Clear() + for item in itemGroup do + let classificationTag = layoutTagToClassificationTag item.Tag + match item with + //| :? NavigableTaggedText as nav when navigation.IsTargetValid nav.Range -> + //flushRuns() + //let navigableTextRun = NavigableTextRun(classificationTag, item.Text, fun () -> navigation.NavigateTo nav.Range) + //currentContainerItems.Add(navigableTextRun :> obj) + | _ when item.Tag = LineBreak -> + flushRuns() + // preserve succesive linebreaks + if currentContainerItems.Count = 0 then + runsCollection.Add(ClassifiedTextRun(PredefinedClassificationTypeNames.Other, System.String.Empty)) + flushRuns() + flushContainer() + | _ -> + let newRun = ClassifiedTextRun(classificationTag, item.Text) + runsCollection.Add(newRun) + flushRuns() + flushContainer() + ContainerElement(ContainerElementStyle.Stacked, finalCollection |> Seq.map box) /// If the XML comment starts with '<' not counting whitespace then treat it as a literal XML comment. /// Otherwise, escape it and surround it with @@ -198,7 +285,7 @@ module internal XmlDocumentation = if not started then started <- true AppendHardLine collector - AppendOnNewLine collector ("SR.ExceptionsHeader()") + AppendOnNewLine collector (SR.ExceptionsHeader()) EnsureHardLine collector collector.Add(tagSpace " ") WriteTypeName collector exnType.Value @@ -210,7 +297,27 @@ module internal XmlDocumentation = type VsThreadToken() = class end let vsToken = VsThreadToken() - + + type FSharpXmlDocumentationProvider(assemblyPath) = + inherit Microsoft.CodeAnalysis.XmlDocumentationProvider() + let xmlPath = Path.ChangeExtension(assemblyPath, ".xml") + + member x.XmlPath = xmlPath + member x.GetDocumentation documentationCommentId = + let xml = base.GetDocumentationForSymbol(documentationCommentId, Globalization.CultureInfo.CurrentCulture, CancellationToken.None) + xml + + override x.GetSourceStream(_cancellationToken) = + new FileStream(xmlPath, FileMode.Open, FileAccess.Read) :> Stream + + override x.Equals(obj) = + if obj :? FSharpXmlDocumentationProvider then + (obj:?>FSharpXmlDocumentationProvider).XmlPath = xmlPath + else + false + + override x.GetHashCode() = xmlPath.GetHashCode() + /// Provide Xml Documentation type Provider((*xmlIndexService:IVsXMLMemberIndexService*)) = /// Index of assembly name to xml member index. @@ -259,9 +366,9 @@ module internal XmlDocumentation = /// ITaggedTextCollector to add to exnCollector: ITaggedTextCollector, /// Name of the library file - _filename:string, + filename:string, /// Signature of the comment - _signature:string, + signature:string, /// Whether to show exceptions showExceptions:bool, /// Whether to show parameters and return @@ -278,7 +385,7 @@ module internal XmlDocumentation = // if Com.Succeeded(ok) then // (this:>IDocumentationBuilder).AppendDocumentationFromProcessedXML(xmlCollector, exnCollector, xml, showExceptions, showParameters, paramName) //| None -> () - (this:>IDocumentationBuilder).AppendDocumentationFromProcessedXML(xmlCollector, exnCollector, "Hi", showExceptions, showParameters, paramName) + (this:>IDocumentationBuilder).AppendDocumentationFromProcessedXML(xmlCollector, exnCollector, FSharpXmlDocumentationProvider(filename).GetDocumentation(signature), showExceptions, showParameters, paramName) with e-> Assert.Exception(e) reraise() @@ -287,7 +394,7 @@ module internal XmlDocumentation = let AppendXmlComment(documentationProvider:IDocumentationBuilder, xmlCollector: ITaggedTextCollector, exnCollector: ITaggedTextCollector, xml, showExceptions, showParameters, paramName) = match xml with | FSharpXmlDoc.None -> () - | FSharpXmlDoc.XmlDocFileSignature(filename,signature) -> + | FSharpXmlDoc.XmlDocFileSignature(filename,signature) -> documentationProvider.AppendDocumentation(xmlCollector, exnCollector, filename, signature, showExceptions, showParameters, paramName) | FSharpXmlDoc.Text(rawXml) -> let processedXml = ProcessXml(rawXml) From 488de37f27681684cfa7abc3a84dd7cd5edaabd9 Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 7 Jan 2020 04:40:14 +0000 Subject: [PATCH 011/101] Clickable hyperlinks --- .../src/FSharp.Editor/FSharp.Editor.fsproj | 20 +++---- .../src/FSharp.Editor/QuickInfo/Views.fs | 3 +- .../WpfNagivableTextRunViewElementFactory.fs | 59 ++++++++++--------- 3 files changed, 43 insertions(+), 39 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 4c1d90bd375..84b9bc6e432 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -138,7 +138,7 @@ - + @@ -173,7 +173,7 @@ FSharp.Editor.Designer.fs - + @@ -181,20 +181,19 @@ Common\LspExternalAccess.fs - - + - + - - - - + + + + @@ -209,6 +208,7 @@ - + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/Views.fs b/vsintegration/src/FSharp.Editor/QuickInfo/Views.fs index 124008420fb..371a240b276 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/Views.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/Views.fs @@ -75,7 +75,8 @@ module internal QuickInfoViewProvider = match item with | :? Layout.NavigableTaggedText as nav when navigation.IsTargetValid nav.Range -> flushRuns() - let navigableTextRun = NavigableTextRun(classificationTag, item.Text, fun () -> navigation.NavigateTo nav.Range) + //let navigableTextRun = NavigableTextRun(classificationTag, item.Text, fun () -> navigation.NavigateTo nav.Range) + let navigableTextRun = ClassifiedTextElement.CreateHyperlink(item.Text, "Navigate to " + item.Text, fun() -> navigation.NavigateTo nav.Range) currentContainerItems.Add(navigableTextRun :> obj) | _ when item.Tag = LineBreak -> flushRuns() diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs b/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs index b38d6d3186f..57fbb4c4823 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs @@ -9,7 +9,8 @@ open System.Windows open Microsoft.VisualStudio.Text.Adornments open Microsoft.VisualStudio.Text.Editor -//open Microsoft.VisualStudio.Utilities +open Microsoft.VisualStudio.Utilities +type UIElement = Xwt.Widget [)>] [] @@ -21,7 +22,7 @@ type WpfNavigableTextRunViewElementFactory viewElementFactoryService:IViewElementFactoryService, settings: EditorOptions ) = - let styles = Microsoft.VisualStudio.FSharp.UIResources.NavStyles() + //let styles = Microsoft.VisualStudio.FSharp.UIResources.NavStyles() interface IViewElementFactory with override __.CreateViewElement<'TView when 'TView: not struct>(textView:ITextView, model:obj) : 'TView = if not (model :? NavigableTextRun) || typeof<'TView> <> typeof then @@ -32,32 +33,34 @@ type WpfNavigableTextRunViewElementFactory let classifiedTextRun = ClassifiedTextRun(navigableTextRun.ClassificationTypeName, navigableTextRun.Text) let classifiedTextElement = ClassifiedTextElement([classifiedTextRun]) let convertedElement = viewElementFactoryService.CreateViewElement(textView, classifiedTextElement) + let link = new Xwt.LinkLabel(navigableTextRun.Text) + //link.Text <- navigableTextRun.Text + //link :> 'TView + //// apply HTML-like styles + //match convertedElement with + //| :? TextBlock as tb -> + //let underlineStyle = + // let key = + // if settings.QuickInfo.DisplayLinks then + // match settings.QuickInfo.UnderlineStyle with + // | QuickInfoUnderlineStyle.Solid -> "solid_underline" + // | QuickInfoUnderlineStyle.Dash -> "dash_underline" + // | QuickInfoUnderlineStyle.Dot -> "dot_underline" + // else + // "no_underline" + // styles.Resources.[key] :?> Style - // apply HTML-like styles - match convertedElement with - | :? TextBlock as tb -> - let underlineStyle = - let key = - if settings.QuickInfo.DisplayLinks then - match settings.QuickInfo.UnderlineStyle with - | QuickInfoUnderlineStyle.Solid -> "solid_underline" - | QuickInfoUnderlineStyle.Dash -> "dash_underline" - | QuickInfoUnderlineStyle.Dot -> "dot_underline" - else - "no_underline" - styles.Resources.[key] :?> Style - - // we need to enclose the generated Inline, which is actually a Run element, - // because fancy styling does not seem to work properly with Runs - let inl = tb.Inlines.FirstInline - let color = inl.Foreground - // clear the color here to make it inherit - inl.ClearValue(Documents.TextElement.ForegroundProperty) |> ignore - // this constructor inserts into TextBlock - Documents.Underline(tb.Inlines.FirstInline, tb.ContentStart, Foreground = color) |> ignore - tb.Resources.[typeof] <- underlineStyle - | _ -> () + //// we need to enclose the generated Inline, which is actually a Run element, + //// because fancy styling does not seem to work properly with Runs + //let inl = tb.Inlines.FirstInline + //let color = inl.Foreground + //// clear the color here to make it inherit + //inl.ClearValue(Documents.TextElement.ForegroundProperty) |> ignore + //// this constructor inserts into TextBlock + //Documents.Underline(tb.Inlines.FirstInline, tb.ContentStart, Foreground = color) |> ignore + //tb.Resources.[typeof] <- underlineStyle + //| _ -> () // add navigation - //convertedElement.MouseDown.Add(fun _ -> navigableTextRun.NavigateAction()) - convertedElement :> obj :?> 'TView + link.ButtonReleased.Add(fun _ -> navigableTextRun.NavigateAction()) + link :> obj :?> 'TView From da5e900032c2fc9d81f21517511b2905733e8098 Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 7 Jan 2020 22:00:43 +0000 Subject: [PATCH 012/101] Syntax and semantic highlighting --- .../Classification/ClassificationService.fs | 41 ++++++++++++-- .../Completion/CompletionService.fs | 10 ++-- .../src/FSharp.Editor/FSharp.Editor.fsproj | 54 +++++++++---------- .../LanguageService/FSharpContentType.fs | 19 ++++--- .../FSharpProjectOptionsManager.fs | 18 +++---- .../LanguageService/LanguageService.fs | 4 +- .../Navigation/FindUsagesService.fs | 43 ++++++++++++++- .../Navigation/NavigableSymbolsService.fs | 6 +-- .../QuickInfo/QuickInfoProvider.fs | 4 +- .../WpfNagivableTextRunViewElementFactory.fs | 2 +- 10 files changed, 141 insertions(+), 60 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs index bb5aabad780..acc13b6155a 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs @@ -21,6 +21,38 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Classification #nowarn "44" open FSharp.Compiler.SourceCodeServices +[] +module internal FSharpClassificationTypes = + let [] Function = ClassificationTypeNames.MethodName// "Function"// "FSharp.Function" + let [] MutableVar = ClassificationTypeNames.LocalName// "FSharp.MutableVar" + let [] Printf = ClassificationTypeNames.MethodName//"FSharp.Printf" + let [] ReferenceType = ClassificationTypeNames.ClassName + let [] Module = ClassificationTypeNames.ClassName //ModuleName + let [] ValueType = ClassificationTypeNames.StructName + let [] Keyword = ClassificationTypeNames.Keyword + let [] Enum = ClassificationTypeNames.EnumName + let [] Property = ClassificationTypeNames.PropertyName//"Property"// "FSharp.Property" + let [] Interface = ClassificationTypeNames.InterfaceName + let [] TypeArgument = ClassificationTypeNames.TypeParameterName + let [] Operator = ClassificationTypeNames.Operator + let [] Disposable = ClassificationTypeNames.ClassName// "FSharp.Disposable" + + let getClassificationTypeName = function + | SemanticClassificationType.ReferenceType -> ReferenceType + | SemanticClassificationType.Module -> Module + | SemanticClassificationType.ValueType -> ValueType + | SemanticClassificationType.Function -> Function + | SemanticClassificationType.MutableVar -> MutableVar + | SemanticClassificationType.Printf -> Printf + | SemanticClassificationType.ComputationExpression + | SemanticClassificationType.IntrinsicFunction -> Keyword + | SemanticClassificationType.UnionCase + | SemanticClassificationType.Enumeration -> Enum + | SemanticClassificationType.Property -> Property + | SemanticClassificationType.Interface -> Interface + | SemanticClassificationType.TypeArgument -> TypeArgument + | SemanticClassificationType.Operator -> Operator + | SemanticClassificationType.Disposable -> Disposable [)>] type internal FSharpClassificationService @@ -32,8 +64,9 @@ type internal FSharpClassificationService static let userOpName = "SemanticColorization" interface IFSharpClassificationService with - // Do not perform classification if we don't have project options (#defines matter) - member __.AddLexicalClassifications(_: SourceText, _: TextSpan, _: List, _: CancellationToken) = () + + member __.AddLexicalClassifications(sourceText: SourceText, textSpan: TextSpan, result: List, cancellationToken: CancellationToken) = + result.AddRange(Tokenizer.getClassifiedSpans(DocumentId.CreateNewId(ProjectId.CreateNewId()), sourceText, textSpan, Some("fake.fs"), [], cancellationToken)) member __.AddSyntacticClassificationsAsync(document: Document, textSpan: TextSpan, result: List, cancellationToken: CancellationToken) = async { @@ -63,8 +96,8 @@ type internal FSharpClassificationService match classificationType with | SemanticClassificationType.Printf -> span | _ -> Tokenizer.fixupSpan(sourceText, span) - //result.Add(ClassifiedSpan(span, FSharpClassificationTypes.getClassificationTypeName(classificationType))) - result.Add(ClassifiedSpan(span, classificationType.ToString())) + result.Add(ClassifiedSpan(span, FSharpClassificationTypes.getClassificationTypeName(classificationType))) + //result.Add(ClassifiedSpan(span, classificationType.ToString())) } |> Async.Ignore |> RoslynHelpers.StartAsyncUnitAsTask cancellationToken diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index 5fe16ae612c..6b185801d87 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -9,12 +9,12 @@ open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Completion open Microsoft.CodeAnalysis.Host open Microsoft.CodeAnalysis.Host.Mef +open Microsoft.CodeAnalysis.ExternalAccess.FSharp +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion open Microsoft.VisualStudio.Shell - - open System open System.ComponentModel.Composition open Microsoft.CodeAnalysis.Editor.Host @@ -135,7 +135,7 @@ type internal FSharpCompletionService [] //[, FSharpConstants.FSharpContentTypeName)>] -[, "code++.F#")>] +[, FSharpConstants.FSharpContentTypeName)>] type internal FSharpCompletionServiceFactory [] @@ -435,7 +435,7 @@ type internal FSharpCompletionSource [)>] [)>] [] -[] +[] type internal CompletionSourceProvider [] ( @@ -461,7 +461,7 @@ open Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.Text.Editor [)>] [] -[] +[] //[] //[] type internal FSharpAsyncCompletionCommitManagerProvider diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 84b9bc6e432..727d5d8b6a0 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -52,10 +52,10 @@ - + - + @@ -172,43 +172,43 @@ PublicResXFileCodeGenerator FSharp.Editor.Designer.fs - - - - - - - - Common\LspExternalAccess.fs - - - - - - - - - - - - - - + - - - + + + + + + + + + + + + Common\LspExternalAccess.fs + + + + + + + + + + + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs index 33c7a96030d..ee4daa24d35 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs @@ -4,15 +4,22 @@ open System.ComponentModel.Composition open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor open Microsoft.VisualStudio.Utilities - +open Microsoft.VisualStudio.Editor type FSharpContentTypeDefinitions() = - let _x = 1 - [] - [] - [] - member val FSharpContentTypeDefinition: ContentTypeDefinition = null with get, set + //let _x = 1 + //[] + ////[] + //[] + //[] + ////[] + //member val FSharpContentTypeDefinition: ContentTypeDefinition = null with get, set [] [] [] member val FSharpSignatureHelpContentTypeDefinition: ContentTypeDefinition = null with get, set + + [] + [] + [] + member val FSharpFileExtension: FileExtensionToContentTypeDefinition = null with get, set \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index b491d01391d..dbf388859d5 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -207,19 +207,19 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) let projectOptions = projectOpts.Value - let sourceFiles = projectOptions.OtherOptions.Where(fun o -> o.StartsWith("/")) - let projectOptions = { projectOptions with SourceFiles = sourceFiles.ToArray() } + //let sourceFiles = projectOptions.OtherOptions.Where(fun o -> o.StartsWith("/")) + //let projectOptions = { projectOptions with SourceFiles = sourceFiles.ToArray() } // This can happen if we didn't receive the callback from HandleCommandLineChanges yet. - if Array.isEmpty projectOptions.SourceFiles then - return None - else - checkerProvider.Checker.InvalidateConfiguration(projectOptions, startBackgroundCompileIfAlreadySeen = false, userOpName = "computeOptions") + //if Array.isEmpty projectOptions.SourceFiles then + // return None + //else + checkerProvider.Checker.InvalidateConfiguration(projectOptions, startBackgroundCompileIfAlreadySeen = false, userOpName = "computeOptions") - let parsingOptions, _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions) + let parsingOptions, _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions) - cache.[projectId] <- (project, parsingOptions, projectOptions) + cache.[projectId] <- (project, parsingOptions, projectOptions) - return Some(parsingOptions, projectOptions) + return Some(parsingOptions, projectOptions) | true, (oldProject, parsingOptions, projectOptions) -> if isProjectInvalidated oldProject project settings then diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 0daccb02607..dfb7d518fca 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -121,7 +121,7 @@ type internal FSharpSettingsFactory ////[, ".ml", 64)>] ////[, ".mli", 64)>] ////[, 101s, CommonPhysicalViewAttributes = Constants.FSharpEditorFactoryPhysicalViewAttributes)>] -//[, ".fs")>] +//[, ".fs")>] //[, ".fsi")>] //[, ".fsx")>] //[, ".fsscript")>] @@ -146,7 +146,7 @@ type internal FSharpSettingsFactory // CodeSenseDelay = 100, // ShowDropDownOptions = true)>] //type internal FSharpPackage() as this = -// inherit AbstractPackage() + //inherit AbstractPackage() // //let mutable vfsiToolWindow = Unchecked.defaultof // //let GetToolWindowAsITestVFSI() = diff --git a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs index f33d23b3291..ef64161c948 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs @@ -13,6 +13,28 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.FindUsages open FSharp.Compiler.Range open FSharp.Compiler.SourceCodeServices +open System.Composition +open System.Threading +open System.Threading.Tasks + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.Editor +open Microsoft.CodeAnalysis.Host.Mef +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor + +open Microsoft.VisualStudio.Shell +open Microsoft.VisualStudio.Shell.Interop +open System +open System; +open System.ComponentModel.Composition; +open Microsoft.CodeAnalysis.Editor.Shared.Extensions; +open Microsoft.CodeAnalysis.Notification; +open Microsoft.CodeAnalysis.Shared.Extensions; +open Microsoft.CodeAnalysis.Text; +open Microsoft.VisualStudio.Commanding; +open Microsoft.VisualStudio.Text; +open Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +open Microsoft.VisualStudio.Utilities; [)>] type internal FSharpFindUsagesService @@ -133,4 +155,23 @@ type internal FSharpFindUsagesService member __.FindImplementationsAsync(document, position, context) = findReferencedSymbolsAsync(document, position, context, false, userOpName) |> RoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken) - \ No newline at end of file + + +//[)>] +//[] +//[] +//type internal FSharpFindReferencesCommandHandler + //[] + //( + // checkerProvider: FSharpCheckerProvider, + // projectInfoManager: FSharpProjectOptionsManager + //) = + + //let gtd = GoToDefinition(checkerProvider.Checker, projectInfoManager) + //let statusBar = StatusBar((*ServiceProvider.GlobalProvider.GetService()*)) + //interface ICommandHandler with + //member __.DisplayName = "FSharp Find References" + //member __.GetCommandState(_args) = + // CommandState.Available + //member __.ExecuteCommand(args, context) = + //true \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs index d22e54a661c..d1eecb82555 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs @@ -45,7 +45,7 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider let document = snapshot.GetOpenDocumentInCurrentContextWithChanges() let! sourceText = document.GetTextAsync() |> liftTaskAsync - statusBar.Message("SR.LocatingSymbol()") + statusBar.Message(SR.LocatingSymbol()) use _ = statusBar.Animate() let gtdTask = gtd.FindDefinitionTask(document, position, cancellationToken) @@ -66,12 +66,12 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider return FSharpNavigableSymbol(navigableItem, symbolSpan, gtd, statusBar) :> INavigableSymbol else - statusBar.TempMessage("SR.CannotDetermineSymbol()") + statusBar.TempMessage(SR.CannotDetermineSymbol()) // The NavigableSymbols API accepts 'null' when there's nothing to navigate to. return null with exc -> - statusBar.TempMessage(String.Format("SR.NavigateToFailed()", Exception.flattenMessage exc)) + statusBar.TempMessage(String.Format(SR.NavigateToFailed(), Exception.flattenMessage exc)) // The NavigableSymbols API accepts 'null' when there's nothing to navigate to. return null diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index 5c6458a507d..6889bb58003 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -23,7 +23,7 @@ open FSharp.Compiler open Internal.Utilities.StructuredFormat open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion - +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor type internal QuickInfo = { StructuredText: FSharpStructuredToolTipText Span: TextSpan @@ -268,7 +268,7 @@ type internal FSharpAsyncQuickInfoSource [)>] [] -[] +[] [] type internal FSharpAsyncQuickInfoSourceProvider [] diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs b/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs index 57fbb4c4823..e56aa889361 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs @@ -12,7 +12,7 @@ open Microsoft.VisualStudio.Text.Editor open Microsoft.VisualStudio.Utilities type UIElement = Xwt.Widget -[)>] +//[)>] [] [, typeof)>] [] From b4aead7e2537678d933dbb80a528811e045921b6 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 8 Jan 2020 12:37:24 +0000 Subject: [PATCH 013/101] Remove syntactic analyzer as it's unused and crashes Mono --- .../Diagnostics/DocumentDiagnosticAnalyzer.fs | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs index 273e0bad4b6..1cfa9b3160e 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs @@ -110,17 +110,20 @@ type internal FSharpDocumentDiagnosticAnalyzer [] () = interface IFSharpDocumentDiagnosticAnalyzer with member this.AnalyzeSyntaxAsync(document: Document, cancellationToken: CancellationToken): Task> = - let projectInfoManager = getProjectInfoManager document - asyncMaybe { - let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) - let! sourceText = document.GetTextAsync(cancellationToken) - let! textVersion = document.GetTextVersionAsync(cancellationToken) - return! - FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(getChecker document, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Syntax) - |> liftAsync - } - |> Async.map (Option.defaultValue ImmutableArray.Empty) - |> RoslynHelpers.StartAsyncAsTask cancellationToken + Task.FromResult ImmutableArray.Empty + // None of the analyzers appear to do syntax checking, only semantic checking + // and this function is causing a StackOverflow on Mono + //let projectInfoManager = getProjectInfoManager document + //asyncMaybe { + // let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + // let! sourceText = document.GetTextAsync(cancellationToken) + // let! textVersion = document.GetTextVersionAsync(cancellationToken) + // return! + // FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(getChecker document, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Syntax) + // |> liftAsync + //} + //|> Async.map (Option.defaultValue ImmutableArray.Empty) + //|> RoslynHelpers.StartAsyncAsTask cancellationToken member this.AnalyzeSemanticsAsync(document: Document, cancellationToken: CancellationToken): Task> = let projectInfoManager = getProjectInfoManager document From 81f40d22335fb430b140e2515a7b88bfca8e2248 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 8 Jan 2020 12:38:06 +0000 Subject: [PATCH 014/101] Navigable symbols --- .../Navigation/NavigableSymbolsService.fs | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs index d1eecb82555..bd9ceb04903 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs @@ -17,6 +17,28 @@ open Microsoft.VisualStudio.Text.Editor open Microsoft.VisualStudio.Shell.Interop //open Microsoft.VisualStudio.Utilities open Microsoft.VisualStudio.Shell +open System.Composition +open System.Threading +open System.Threading.Tasks + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.Editor +open Microsoft.CodeAnalysis.Host.Mef +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor + +open Microsoft.VisualStudio.Shell +open Microsoft.VisualStudio.Shell.Interop +open System +open System; +open System.ComponentModel.Composition; +open Microsoft.CodeAnalysis.Editor.Shared.Extensions; +open Microsoft.CodeAnalysis.Notification; +open Microsoft.CodeAnalysis.Shared.Extensions; +open Microsoft.CodeAnalysis.Text; +open Microsoft.VisualStudio.Commanding; +open Microsoft.VisualStudio.Text; +open Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +open Microsoft.VisualStudio.Utilities; [] type internal FSharpNavigableSymbol(item: FSharpNavigableItem, span: SnapshotSpan, gtd: GoToDefinition, statusBar: StatusBar) = @@ -45,8 +67,8 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider let document = snapshot.GetOpenDocumentInCurrentContextWithChanges() let! sourceText = document.GetTextAsync() |> liftTaskAsync - statusBar.Message(SR.LocatingSymbol()) - use _ = statusBar.Animate() + //statusBar.Message(SR.LocatingSymbol()) + //use _ = statusBar.Animate() let gtdTask = gtd.FindDefinitionTask(document, position, cancellationToken) @@ -55,7 +77,7 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider try // This call to Wait() is fine because we want to be able to provide the error message in the status bar. gtdTask.Wait() - statusBar.Clear() + //statusBar.Clear() if gtdTask.Status = TaskStatus.RanToCompletion && gtdTask.Result.IsSome then let navigableItem, range = gtdTask.Result.Value @@ -66,12 +88,12 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider return FSharpNavigableSymbol(navigableItem, symbolSpan, gtd, statusBar) :> INavigableSymbol else - statusBar.TempMessage(SR.CannotDetermineSymbol()) + //statusBar.TempMessage(SR.CannotDetermineSymbol()) // The NavigableSymbols API accepts 'null' when there's nothing to navigate to. return null with exc -> - statusBar.TempMessage(String.Format(SR.NavigateToFailed(), Exception.flattenMessage exc)) + //statusBar.TempMessage(String.Format(SR.NavigateToFailed(), Exception.flattenMessage exc)) // The NavigableSymbols API accepts 'null' when there's nothing to navigate to. return null @@ -83,9 +105,9 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider disposed <- true [)>] -//[] -//[] -//[] +[] +[] +[] type internal FSharpNavigableSymbolService [] ( From 9ecda4abf1ecc860a798431b183d81f69685e151 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 8 Jan 2020 23:34:18 +0000 Subject: [PATCH 015/101] Bump FCS --- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 727d5d8b6a0..80f3b00c250 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -197,7 +197,7 @@ Common\LspExternalAccess.fs - + From aee2642968c44f33613690bdbb451634e81fbe45 Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 14 Feb 2020 15:50:19 +0000 Subject: [PATCH 016/101] stash --- Directory.Build.props | 6 - Directory.Build.targets | 5 - FSharpBuild.Directory.Build.props | 109 --------- FSharpBuild.Directory.Build.targets | 64 ----- vsintegration/Directory.Build.props | 12 - vsintegration/Directory.Build.targets | 23 -- vsintegration/src/Directory.Build.props | 12 - .../src/FSharp.Editor/Common/Logging.fs | 9 +- .../Completion/CompletionProvider.fs | 2 +- .../Completion/CompletionService.fs | 26 +- .../Diagnostics/DocumentDiagnosticAnalyzer.fs | 24 +- .../Diagnostics/UnusedDeclarationsAnalyzer.fs | 2 +- .../UnusedOpensDiagnosticAnalyzer.fs | 20 ++ .../FSharp.Editor/FSharp.Editor.Mac.fsproj | 227 ++++++++++++++++++ .../src/FSharp.Editor/FSharp.Editor.fsproj | 41 ++-- .../src/FSharp.Editor/FSharp.addin.xml | 3 +- .../Formatting/EditorFormattingService.fs | 4 +- .../FSharpProjectOptionsManager.fs | 129 +++++----- .../LanguageService/IProjectSite.fs | 2 +- .../LanguageService/LanguageService.fs | 2 +- .../FSharp.Editor/Options/EditorOptionsMac.fs | 10 +- .../src/FSharp.Editor/Properties/AddinInfo.fs | 7 +- 22 files changed, 383 insertions(+), 356 deletions(-) delete mode 100644 Directory.Build.props delete mode 100644 Directory.Build.targets delete mode 100644 FSharpBuild.Directory.Build.props delete mode 100644 FSharpBuild.Directory.Build.targets delete mode 100644 vsintegration/Directory.Build.props delete mode 100644 vsintegration/Directory.Build.targets delete mode 100644 vsintegration/src/Directory.Build.props create mode 100644 vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj diff --git a/Directory.Build.props b/Directory.Build.props deleted file mode 100644 index e9c2a5c5e99..00000000000 --- a/Directory.Build.props +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/Directory.Build.targets b/Directory.Build.targets deleted file mode 100644 index 08da3ab0966..00000000000 --- a/Directory.Build.targets +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/FSharpBuild.Directory.Build.props b/FSharpBuild.Directory.Build.props deleted file mode 100644 index 72afe7c03d7..00000000000 --- a/FSharpBuild.Directory.Build.props +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - - true - - - - - $(RepoRoot)src - $(ArtifactsDir)\SymStore - $(ArtifactsDir)\Bootstrap - 4.4.0 - 1182;0025;$(WarningsAsErrors) - - - - - - $(RestoreAdditionalProjectSources);$(ArtifactsPackagesDir) - $(ArtifactsPackagesDir) - - - $(NUGET_PACKAGES) - $(UserProfile)\.nuget\packages\ - $(HOME)/.nuget/packages/ - - - $(NuGetPackageRoot)\ - $(NuGetPackageRoot)/ - - - true - - - - - /usr - /Library/Frameworks/Mono.framework/Versions/Current - $(MonoRoot)/lib/mono - true - $(MonoLibFolder)/4.5-api - $(MonoLibFolder)/4.5.1-api - $(MonoLibFolder)/4.5.2-api - $(MonoLibFolder)/4.6-api - $(MonoLibFolder)/4.6.1-api - $(MonoLibFolder)/4.6.2-api - $(MonoLibFolder)/4.7-api - $(MonoLibFolder)/4.7.1-api - $(MonoLibFolder)/4.7.2-api;$(MonoLibFolder)/4.7.2-api/Facades - - - - - Microsoft - - - $(FSharpSourcesRoot)\fsharp\test.snk - false - STRONG_NAME_FSHARP_COMPILER_WITH_TEST_KEY;$(DefineConstants) - - - - - false - true - - - - - false - false - https://github.com/Microsoft/visualfsharp - git - - - - <_DotGitDir>$(RepoRoot).git - <_HeadFileContent Condition="Exists('$(_DotGitDir)/HEAD')">$([System.IO.File]::ReadAllText('$(_DotGitDir)/HEAD').Trim()) - <_RefPath Condition="$(_HeadFileContent.StartsWith('ref: '))">$(_DotGitDir)/$(_HeadFileContent.Substring(5)) - $(BUILD_SOURCEVERSION) - $([System.IO.File]::ReadAllText('$(_RefPath)').Trim()) - - - - - $(NoWarn);FS2003 - true - embedded - fs - false - true - - - - $(DefineConstants);TESTING_ON_LINUX - - - - - $(ProtoOutputPath)\fsc\Microsoft.FSharp.Targets - $(ProtoOutputPath)\fsc\Microsoft.FSharp.NetSdk.props - $(ProtoOutputPath)\fsc\Microsoft.FSharp.NetSdk.targets - $(ProtoOutputPath)\fsc\Microsoft.FSharp.Overrides.NetSdk.targets - - - diff --git a/FSharpBuild.Directory.Build.targets b/FSharpBuild.Directory.Build.targets deleted file mode 100644 index 7548cef7acf..00000000000 --- a/FSharpBuild.Directory.Build.targets +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - <__TargetFilePath>@(NoneSubstituteText->'$(IntermediateOutputPath)%(Filename)%(Extension)') - <__TargetFileName>@(NoneSubstituteText->'%(Filename)%(Extension)') - - <_ReplacementText>$([System.IO.File]::ReadAllText('%(NoneSubstituteText.FullPath)')) - <_ReplacementText Condition="'%(NoneSubstituteText.Pattern1)' != ''">$(_ReplacementText.Replace('%(NoneSubstituteText.Pattern1)', '%(NoneSubstituteText.Replacement1)')) - <_ReplacementText Condition="'%(NoneSubstituteText.Pattern2)' != ''">$(_ReplacementText.Replace('%(NoneSubstituteText.Pattern2)', '%(NoneSubstituteText.Replacement2)')) - - <_CopyToOutputDirectory Condition="'%(NoneSubstituteText.CopyToOutputDirectory)' != ''">%(NoneSubstituteText.CopyToOutputDirectory) - <_CopyToOutputDirectory Condition="'%(NoneSubstituteText.CopyToOutputDirectory)' == ''">Never - - - - - - - - - - - - - - - - <_BuildPropertyLines Remove="@(_BuildPropertyLines)" /> - <_BuildPropertyLines Include="// <auto-generated >" /> - <_BuildPropertyLines Include="// <Generated by the FSharp WriteCodeFragment class./>" /> - <_BuildPropertyLines Include="// </auto-generated/>" /> - <_BuildPropertyLines Include="//" /> - <_BuildPropertyLines Include="module internal FSharp.BuildProperties" /> - <_BuildPropertyLines Include="let fsProductVersion = "$(FSPRODUCTVERSION)"" /> - <_BuildPropertyLines Include="let fsLanguageVersion = "$(FSLANGUAGEVERSION)"" /> - - - - - - - - - - - - - diff --git a/vsintegration/Directory.Build.props b/vsintegration/Directory.Build.props deleted file mode 100644 index eebd6774fae..00000000000 --- a/vsintegration/Directory.Build.props +++ /dev/null @@ -1,12 +0,0 @@ - - - - net472 - v4.7.2 - true - true - - - - - diff --git a/vsintegration/Directory.Build.targets b/vsintegration/Directory.Build.targets deleted file mode 100644 index bc5c6d7195c..00000000000 --- a/vsintegration/Directory.Build.targets +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - true - - - - - - - - - - - - - - - - - diff --git a/vsintegration/src/Directory.Build.props b/vsintegration/src/Directory.Build.props deleted file mode 100644 index 8256f7b79da..00000000000 --- a/vsintegration/src/Directory.Build.props +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - false - false - false - false - - - diff --git a/vsintegration/src/FSharp.Editor/Common/Logging.fs b/vsintegration/src/FSharp.Editor/Common/Logging.fs index 2ecb2d6a8ac..59f24b42b98 100644 --- a/vsintegration/src/FSharp.Editor/Common/Logging.fs +++ b/vsintegration/src/FSharp.Editor/Common/Logging.fs @@ -6,7 +6,6 @@ open System.ComponentModel.Composition open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.FSharp.Editor - [] type LogType = | Info @@ -46,11 +45,11 @@ type [] Logger [] //| _ -> None None - static let mutable globalServiceProvider: IServiceProvider option = None + //static let mutable globalServiceProvider: IServiceProvider option = None - static member GlobalServiceProvider - with get () = globalServiceProvider |> Option.defaultValue (ServiceProvider.GlobalProvider :> IServiceProvider) - and set v = globalServiceProvider <- Some v + //static member GlobalServiceProvider + //with get () = globalServiceProvider |> Option.defaultValue (ServiceProvider.GlobalProvider :> IServiceProvider) + //and set v = globalServiceProvider <- Some v member __.FSharpLoggingPane with get () = diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index 52a003747ec..16fc043af15 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -54,7 +54,7 @@ type internal FSharpCompletionProvider let checker = checkerProvider.Checker - + let settings: EditorOptions = workspace.Services.GetService() //let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder(serviceProvider.XMLMemberIndexService) diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index 6b185801d87..3fd67c24bee 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -137,21 +137,21 @@ type internal FSharpCompletionService //[, FSharpConstants.FSharpContentTypeName)>] [, FSharpConstants.FSharpContentTypeName)>] -type internal FSharpCompletionServiceFactory - [] - ( - //serviceProvider: SVsServiceProvider, - checkerProvider: FSharpCheckerProvider, +//type internal FSharpCompletionServiceFactory + //[] + //( + // //serviceProvider: SVsServiceProvider, + // checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager, - assemblyContentProvider: AssemblyContentProvider, - settings: EditorOptions - ) = + // projectInfoManager: FSharpProjectOptionsManager, + // assemblyContentProvider: AssemblyContentProvider, + // settings: EditorOptions + //) = - interface ILanguageServiceFactory with - member this.CreateLanguageService(hostLanguageServices: HostLanguageServices) : ILanguageService = - upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, projectInfoManager, assemblyContentProvider, settings) - //upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, new FSharpProjectOptionsManager(, assemblyContentProvider, settings) + //interface ILanguageServiceFactory with + //member this.CreateLanguageService(hostLanguageServices: HostLanguageServices) : ILanguageService = + //upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, projectInfoManager, assemblyContentProvider, settings) + ////upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, new FSharpProjectOptionsManager(, assemblyContentProvider, settings) type internal FSharpCompletionSource (textView: ITextView, checkerProvider, projectInfoManager, assemblyContentProvider) = diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs index 1cfa9b3160e..d9fe8b811d2 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs @@ -110,20 +110,20 @@ type internal FSharpDocumentDiagnosticAnalyzer [] () = interface IFSharpDocumentDiagnosticAnalyzer with member this.AnalyzeSyntaxAsync(document: Document, cancellationToken: CancellationToken): Task> = - Task.FromResult ImmutableArray.Empty + //Task.FromResult ImmutableArray.Empty // None of the analyzers appear to do syntax checking, only semantic checking // and this function is causing a StackOverflow on Mono - //let projectInfoManager = getProjectInfoManager document - //asyncMaybe { - // let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) - // let! sourceText = document.GetTextAsync(cancellationToken) - // let! textVersion = document.GetTextVersionAsync(cancellationToken) - // return! - // FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(getChecker document, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Syntax) - // |> liftAsync - //} - //|> Async.map (Option.defaultValue ImmutableArray.Empty) - //|> RoslynHelpers.StartAsyncAsTask cancellationToken + let projectInfoManager = getProjectInfoManager document + asyncMaybe { + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! sourceText = document.GetTextAsync(cancellationToken) + let! textVersion = document.GetTextVersionAsync(cancellationToken) + return! + FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(getChecker document, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Syntax) + |> liftAsync + } + |> Async.map (Option.defaultValue ImmutableArray.Empty) + |> RoslynHelpers.StartAsyncAsTask cancellationToken member this.AnalyzeSemanticsAsync(document: Document, cancellationToken: CancellationToken): Task> = let projectInfoManager = getProjectInfoManager document diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs index ff7c43839d0..a40c3aed955 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs @@ -21,7 +21,7 @@ type internal UnusedDeclarationsAnalyzer [] () = static let userOpName = "UnusedDeclarationsAnalyzer" let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService().FSharpProjectOptionsManager let getChecker (document: Document) = document.Project.Solution.Workspace.Services.GetService().Checker - + let isPotentiallyUnusedDeclaration (symbol: FSharpSymbol) : bool = match symbol with // Determining that a record, DU or module is used anywhere requires inspecting all their enclosed entities (fields, cases and func / vals) diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs index c79027b0dff..099e2c1a40f 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs @@ -46,6 +46,26 @@ type internal UnusedOpensDiagnosticAnalyzer [] () = interface IFSharpUnusedOpensDiagnosticAnalyzer with member this.AnalyzeSemanticsAsync(descriptor, document: Document, cancellationToken: CancellationToken) = + + //TextViewFromDocument(Document document) + //{ + // return document?.GetContent(); + //} + + //private Document DocumentFromTextView(ITextView textView) + //{ + // return IdeApp.Workbench.Documents.FirstOrDefault(doc => TextViewFromDocument(doc) == textView); + //} + + //private Document DocumentFromTextBuffer(ITextBuffer textBuffer) + //{ + let isOpen = + MonoDevelop.Ide.IdeApp.Workbench.Documents + |> Seq.exists(fun d -> d.FilePath |> string = document.FilePath) + + if not isOpen then + Task.FromResult ImmutableArray.Empty + else asyncMaybe { do Trace.TraceInformation("{0:n3} (start) UnusedOpensAnalyzer", DateTime.Now.TimeOfDay.TotalSeconds) do! Async.Sleep DefaultTuning.UnusedOpensAnalyzerInitialDelay |> liftAsync // be less intrusive, give other work priority most of the time diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj new file mode 100644 index 00000000000..5fcaaa126ff --- /dev/null +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj @@ -0,0 +1,227 @@ + + + + + + + true + + + + + Debug + AnyCPU + {4C10F8F9-3816-4647-BA6E-85F5DE39883B} + FSharp.Editor + FSharp.Editor + False + False + + $(MDFrameworkVersion) + + win + true + --publicsign + ..\..\..\..\vsmac\main\msbuild\MonoDevelop-Public.snk + --warnon:1182 + Program + true + $(MSBuildProjectDirectory)\..\..\..\build\bin\MonoDevelop.exe + $(MSBuildProjectDirectory)\..\..\..\build\bin + + portable + false + ..\..\..\..\vsmac\main\build\AddIns\FSharp.Editor + 3 + ..\..\..\..\vsmac\main\build\AddIns\FSharp.Editor\FSharp.Editor.XML + false + --warnon:11111182 --subsystemversion:6.00 --simpleresolution --nocopyfsharpcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FSharp.Editor + $(VSAssemblyVersion) + $PackageFolder$\FSharp.Editor.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FSharp.Editor.resx + + + + + + + + + + + + + + true + Microsoft.VisualStudio.FSharp.Editor.SR + PublicResXFileCodeGenerator + FSharp.Editor.Designer.fs + + + + {91DD5A2D-9FE3-4C3C-9253-876141874DAD} + Mono.Addins + + + {3F5B5BDA-69D5-441A-8142-AA25C998A997} + MonoDevelop.TextEditor + + + + + {7525BB88-6142-4A26-93B9-A30C6983390A} + MonoDevelop.Core + + + + + + {27096E7F-C91C-4AC6-B289-6897A701DF21} + MonoDevelop.Ide + + + + + + + + + + + {4C10F8F9-3816-4647-BA6E-85F5DE39883A} + MonoDevelop.FSharp + + + + + + + + + + + + + + + diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 80f3b00c250..c295b354650 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -57,6 +57,7 @@ + @@ -83,7 +84,7 @@ - + @@ -143,9 +144,9 @@ - + - + @@ -172,43 +173,47 @@ PublicResXFileCodeGenerator FSharp.Editor.Designer.fs - - + - + + + + + + + - - - - - Common\LspExternalAccess.fs + + - - - - + - - + + + + + + + - \ No newline at end of file + diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index b11b05405f0..0bd1fa443a5 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -1,11 +1,12 @@  - + + diff --git a/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs b/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs index 4cc4b10c5a2..8033fca4d02 100644 --- a/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs +++ b/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs @@ -14,7 +14,7 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor open FSharp.Compiler.SourceCodeServices open System.Threading -open System.Windows.Forms +//open System.Windows.Forms [)>] type internal FSharpEditorFormattingService @@ -189,7 +189,7 @@ type internal FSharpEditorFormattingService |> RoslynHelpers.StartAsyncAsTask cancellationToken override this.GetFormattingChangesOnPasteAsync (document, span, cancellationToken) = - let currentClipboard = Clipboard.GetText() + let currentClipboard = System.Windows.Clipboard.GetDataObject().GetData(System.Windows.DataFormats.Text) :?> string this.OnPasteAsync (document, span, currentClipboard, cancellationToken) |> RoslynHelpers.StartAsyncAsTask cancellationToken diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index dbf388859d5..fad4e32ed48 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -21,56 +21,56 @@ open System.Threading open Microsoft.VisualStudio.LanguageServices.Implementation.TaskList open Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices -[] -module private FSharpProjectOptionsHelpers = - - let mapCpsProjectToSite(project:Project, cpsCommandLineOptions: IDictionary) = - let sourcePaths, referencePaths, options = - match cpsCommandLineOptions.TryGetValue(project.Id) with - | true, (sourcePaths, options) -> sourcePaths, [||], options - | false, _ -> [||], [||], [||] - let mutable errorReporter = Unchecked.defaultof<_> - { - new IProjectSite with - member __.Description = project.Name - member __.CompilationSourceFiles = sourcePaths - member __.CompilationOptions = - Array.concat [options; referencePaths |> Array.map(fun r -> "-r:" + r)] - member __.CompilationReferences = referencePaths - member site.CompilationBinOutputPath = site.CompilationOptions |> Array.tryPick (fun s -> if s.StartsWith("-o:") then Some s.[3..] else None) - 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 = None - member __.BuildErrorReporter with get () = errorReporter and set (v) = errorReporter <- v - } - - let hasProjectVersionChanged (oldProject: Project) (newProject: Project) = - oldProject.Version <> newProject.Version - - let hasDependentVersionChanged (oldProject: Project) (newProject: Project) = - let oldProjectRefs = oldProject.ProjectReferences - let newProjectRefs = newProject.ProjectReferences - oldProjectRefs.Count() <> newProjectRefs.Count() || - (oldProjectRefs, newProjectRefs) - ||> Seq.exists2 (fun p1 p2 -> - let doesProjectIdDiffer = p1.ProjectId <> p2.ProjectId - let p1 = oldProject.Solution.GetProject(p1.ProjectId) - let p2 = newProject.Solution.GetProject(p2.ProjectId) - doesProjectIdDiffer || p1.Version <> p2.Version - ) - - let isProjectInvalidated (oldProject: Project) (newProject: Project) (settings: EditorOptions) = - let hasProjectVersionChanged = hasProjectVersionChanged oldProject newProject - if settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences then - hasProjectVersionChanged || hasDependentVersionChanged oldProject newProject - else - hasProjectVersionChanged +//[] +//module private FSharpProjectOptionsHelpers = + + //let mapCpsProjectToSite(project:Project, cpsCommandLineOptions: IDictionary) = + // let sourcePaths, referencePaths, options = + // match cpsCommandLineOptions.TryGetValue(project.Id) with + // | true, (sourcePaths, options) -> sourcePaths, [||], options + // | false, _ -> [||], [||], [||] + // let mutable errorReporter = Unchecked.defaultof<_> + // { + // new IProjectSite with + // member __.Description = project.Name + // member __.CompilationSourceFiles = sourcePaths + // member __.CompilationOptions = + // Array.concat [options; referencePaths |> Array.map(fun r -> "-r:" + r)] + // member __.CompilationReferences = referencePaths + // member site.CompilationBinOutputPath = site.CompilationOptions |> Array.tryPick (fun s -> if s.StartsWith("-o:") then Some s.[3..] else None) + // 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 = None + // //member __.BuildErrorReporter with get () = errorReporter and set (v) = errorReporter <- v + // } + + //let hasProjectVersionChanged (oldProject: Project) (newProject: Project) = + // oldProject.Version <> newProject.Version + + //let hasDependentVersionChanged (oldProject: Project) (newProject: Project) = + // let oldProjectRefs = oldProject.ProjectReferences + // let newProjectRefs = newProject.ProjectReferences + // oldProjectRefs.Count() <> newProjectRefs.Count() || + // (oldProjectRefs, newProjectRefs) + // ||> Seq.exists2 (fun p1 p2 -> + // let doesProjectIdDiffer = p1.ProjectId <> p2.ProjectId + // let p1 = oldProject.Solution.GetProject(p1.ProjectId) + // let p2 = newProject.Solution.GetProject(p2.ProjectId) + // doesProjectIdDiffer || p1.Version <> p2.Version + // ) + + //let isProjectInvalidated (oldProject: Project) (newProject: Project) (settings: EditorOptions) = + //let hasProjectVersionChanged = hasProjectVersionChanged oldProject newProject + //if settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences then + // hasProjectVersionChanged || hasDependentVersionChanged oldProject newProject + //else + //hasProjectVersionChanged [] type private FSharpProjectOptionsMessage = @@ -86,7 +86,7 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) // Hack to store command line options from HandleCommandLineChanges let cpsCommandLineOptions = ConcurrentDictionary() - let legacyProjectSites = ConcurrentDictionary() + //let legacyProjectSites = ConcurrentDictionary() let cache = Dictionary() let singleFileCache = Dictionary() @@ -163,16 +163,19 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) //| None -> canBail <- true //| Some(_, projectOptions) -> referencedProjects.Add(referencedProject.OutputFilePath, projectOptions) - if canBail then - return None - else + //match tryGetProjectSite project with //| None -> return None //| Some projectSite -> - + let fsharpProject = MonoDevelop.Ide.IdeApp.TypeSystemService.GetMonoProject(project) :?> MonoDevelop.FSharp.FSharpProject + let! refs = fsharpProject.GetReferences(MonoDevelop.FSharp.CompilerArguments.getConfig()) |> Async.AwaitTask + canBail <- refs.Count = 0 + if canBail then + return None + else MonoDevelop.FSharp.MDLanguageService.DisableVirtualFileSystem() - let projectOpts = MonoDevelop.FSharp.MDLanguageService.Instance.GetProjectCheckerOptions(project.FilePath) + let projectOpts = MonoDevelop.FSharp.MDLanguageService.Instance.GetProjectCheckerOptions(project.FilePath, [], refs) //let otherOptions = // project.ProjectReferences // |> Seq.map (fun x -> "-r:" + project.Solution.GetProject(x.ProjectId).OutputFilePath) @@ -222,10 +225,10 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) return Some(parsingOptions, projectOptions) | true, (oldProject, parsingOptions, projectOptions) -> - if isProjectInvalidated oldProject project settings then - cache.Remove(projectId) |> ignore - return! tryComputeOptions project - else + //if isProjectInvalidated oldProject project settings then + // cache.Remove(projectId) |> ignore + // return! tryComputeOptions project + //else return Some(parsingOptions, projectOptions) } @@ -267,7 +270,7 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) | FSharpProjectOptionsMessage.ClearOptions(projectId) -> cache.Remove(projectId) |> ignore - legacyProjectSites.TryRemove(projectId) |> ignore + //legacyProjectSites.TryRemove(projectId) |> ignore | FSharpProjectOptionsMessage.ClearSingleFileOptionsCache(documentId) -> singleFileCache.Remove(documentId) |> ignore } @@ -289,8 +292,8 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) member __.SetCpsCommandLineOptions(projectId, sourcePaths, options) = cpsCommandLineOptions.[projectId] <- (sourcePaths, options) - member __.SetLegacyProjectSite (projectId, projectSite) = - legacyProjectSites.[projectId] <- projectSite + member __.SetLegacyProjectSite (projectId, projectSite) = () + //legacyProjectSites.[projectId] <- projectSite member __.TryGetCachedOptionsByProjectId(projectId) = match cache.TryGetValue(projectId) with diff --git a/vsintegration/src/FSharp.Editor/LanguageService/IProjectSite.fs b/vsintegration/src/FSharp.Editor/LanguageService/IProjectSite.fs index 0b3f65d3627..0d778521a15 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/IProjectSite.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/IProjectSite.fs @@ -43,7 +43,7 @@ and internal IProjectSite = abstract Description : string /// The error list task reporter - abstract BuildErrorReporter : Microsoft.VisualStudio.Shell.Interop.IVsLanguageServiceBuildErrorReporter2 option with get, set + //abstract BuildErrorReporter : Microsoft.VisualStudio.Shell.Interop.IVsLanguageServiceBuildErrorReporter2 option with get, set /// False type resolution errors are invalid. This occurs with orphaned source files. The prior /// type checking state is unknown. In this case we don't want to squiggle the type checking files. diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index dfb7d518fca..5956801f0bf 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -15,7 +15,7 @@ open Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.LanguageServices open Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem -open Microsoft.VisualStudio.LanguageServices.ProjectSystem +//open Microsoft.VisualStudio.LanguageServices.ProjectSystem open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.Text.Outlining diff --git a/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs b/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs index 0eaf862dcb8..979bcc0dab1 100644 --- a/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs +++ b/vsintegration/src/FSharp.Editor/Options/EditorOptionsMac.fs @@ -107,9 +107,11 @@ type EditorOptions //[)>] serviceProvider: IServiceProvider ) = + static let instance = EditorOptions() + //let c = MonoDevelop.Ide.Composition.CompositionManager. let store = SettingsStore((*serviceProvider*)) - + do store.Register QuickInfoOptions.Default store.Register CodeFixesOptions.Default @@ -127,6 +129,8 @@ type EditorOptions member __.CodeLens: CodeLensOptions = store.Get() member __.Formatting : FormattingOptions = store.Get() + + static member Instance = instance interface Microsoft.CodeAnalysis.Host.IWorkspaceService interface IPersistSettings with @@ -136,5 +140,5 @@ type EditorOptions [] module internal WorkspaceSettingFromDocumentExtension = type Microsoft.CodeAnalysis.Document with - member this.FSharpOptions = - this.Project.Solution.Workspace.Services.GetService() : EditorOptions + member this.FSharpOptions = EditorOptions.Instance + //this.Project.Solution.Workspace.Services.GetService() : EditorOptions diff --git a/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs b/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs index 8b160b6e906..0cf621d0ad6 100644 --- a/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs +++ b/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs @@ -2,7 +2,6 @@ open Mono.Addins [] @@ -11,7 +10,7 @@ open Mono.Addins [] [] -//[] -//[] - +[] +[] +[] () \ No newline at end of file From 069f19879e5f02ab0a3879dbabe79975d87d4ccd Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 14 Feb 2020 16:15:51 +0000 Subject: [PATCH 017/101] stash --- vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj index 5fcaaa126ff..707fdc471a3 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj @@ -1,6 +1,6 @@  - - + + From be8082bf9576963e244509ad82a893a5f8e03185 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 17 Feb 2020 09:28:19 +0000 Subject: [PATCH 018/101] Update project file --- .../FSharp.Editor/FSharp.Editor.Mac.fsproj | 38 +++++++++---------- .../src/FSharp.Editor/FSharp.addin.xml | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj index 707fdc471a3..29edd44b15a 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj @@ -3,9 +3,9 @@ - + @@ -22,7 +22,7 @@ win true --publicsign - ..\..\..\..\vsmac\main\msbuild\MonoDevelop-Public.snk + ..\..\..\..\..\msbuild\MonoDevelop-Public.snk --warnon:1182 Program true @@ -31,9 +31,9 @@ portable false - ..\..\..\..\vsmac\main\build\AddIns\FSharp.Editor + ..\..\..\..\..\build\AddIns\FSharp.Editor 3 - ..\..\..\..\vsmac\main\build\AddIns\FSharp.Editor\FSharp.Editor.XML + ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML false --warnon:11111182 --subsystemversion:6.00 --simpleresolution --nocopyfsharpcore @@ -178,27 +178,15 @@ FSharp.Editor.Designer.fs - - {91DD5A2D-9FE3-4C3C-9253-876141874DAD} - Mono.Addins - - + {3F5B5BDA-69D5-441A-8142-AA25C998A997} MonoDevelop.TextEditor - - {7525BB88-6142-4A26-93B9-A30C6983390A} - MonoDevelop.Core - - - {27096E7F-C91C-4AC6-B289-6897A701DF21} - MonoDevelop.Ide - @@ -207,10 +195,22 @@ - + + {7525BB88-6142-4A26-93B9-A30C6983390A} + MonoDevelop.Core + + + {27096E7F-C91C-4AC6-B289-6897A701DF21} + MonoDevelop.Ide + + {4C10F8F9-3816-4647-BA6E-85F5DE39883A} MonoDevelop.FSharp + + {91DD5A2D-9FE3-4C3C-9253-876141874DAD} + Mono.Addins + diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index 0bd1fa443a5..7f2251879e3 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -6,7 +6,7 @@ - + From eeb273490b19c5e9061652d0046fc4d3d6ed1d82 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 17 Feb 2020 10:15:49 +0000 Subject: [PATCH 019/101] Update project file names --- .../FSharp.Editor/FSharp.Editor.Mac.fsproj | 227 ------------------ .../FSharp.Editor/FSharp.Editor.Win.fsproj | 219 +++++++++++++++++ .../src/FSharp.Editor/FSharp.Editor.fsproj | 191 ++++++++------- 3 files changed, 320 insertions(+), 317 deletions(-) delete mode 100644 vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj create mode 100644 vsintegration/src/FSharp.Editor/FSharp.Editor.Win.fsproj diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj deleted file mode 100644 index 29edd44b15a..00000000000 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.Mac.fsproj +++ /dev/null @@ -1,227 +0,0 @@ - - - - - - - - - - Debug - AnyCPU - {4C10F8F9-3816-4647-BA6E-85F5DE39883B} - FSharp.Editor - FSharp.Editor - False - False - - $(MDFrameworkVersion) - - win - true - --publicsign - ..\..\..\..\..\msbuild\MonoDevelop-Public.snk - --warnon:1182 - Program - true - $(MSBuildProjectDirectory)\..\..\..\build\bin\MonoDevelop.exe - $(MSBuildProjectDirectory)\..\..\..\build\bin - - portable - false - ..\..\..\..\..\build\AddIns\FSharp.Editor - 3 - ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML - false - --warnon:11111182 --subsystemversion:6.00 --simpleresolution --nocopyfsharpcore - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FSharp.Editor - $(VSAssemblyVersion) - $PackageFolder$\FSharp.Editor.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FSharp.Editor.resx - - - - - - - - - - - - - - true - Microsoft.VisualStudio.FSharp.Editor.SR - PublicResXFileCodeGenerator - FSharp.Editor.Designer.fs - - - - {3F5B5BDA-69D5-441A-8142-AA25C998A997} - MonoDevelop.TextEditor - - - - - - - - - - - - - - - - {7525BB88-6142-4A26-93B9-A30C6983390A} - MonoDevelop.Core - - - {27096E7F-C91C-4AC6-B289-6897A701DF21} - MonoDevelop.Ide - - - {4C10F8F9-3816-4647-BA6E-85F5DE39883A} - MonoDevelop.FSharp - - - {91DD5A2D-9FE3-4C3C-9253-876141874DAD} - Mono.Addins - - - - - - - - - - - - - - - diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.Win.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.Win.fsproj new file mode 100644 index 00000000000..c295b354650 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.Win.fsproj @@ -0,0 +1,219 @@ + + + Library + $(NoWarn);75 + $(NoWarn);44 + + true + true + $(SystemValueTupleVersion) + $(OtherFlags) --warnon:1182 --subsystemversion:6.00 + false + net472 + + + embedded + false + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor + 0 + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor\FSharp.Editor.XML + false + + + portable + false + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor + 3 + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor\FSharp.Editor.XML + false + --warnon:11111182 --subsystemversion:6.00 --simpleresolution --nocopyfsharpcore + + + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor + 4 + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor\FSharp.Editor.XML + false + + + ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FSharp.Editor + $(VSAssemblyVersion) + $PackageFolder$\FSharp.Editor.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FSharp.Editor.resx + + + + + + + + + + + + true + Microsoft.VisualStudio.FSharp.Editor.SR + PublicResXFileCodeGenerator + FSharp.Editor.Designer.fs + + + + + + + + + + + + + + + + + + + + + + + + + Common\LspExternalAccess.fs + + + + + + + + + + + + + + + + + + + + diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index c295b354650..034c7d206b4 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -1,63 +1,68 @@ - + + + + + + + + - Library - $(NoWarn);75 - $(NoWarn);44 - - true - true - $(SystemValueTupleVersion) - $(OtherFlags) --warnon:1182 --subsystemversion:6.00 - false - net472 - - - embedded - false - ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor - 0 - ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor\FSharp.Editor.XML - false - - + Debug + AnyCPU + {4C10F8F9-3816-4647-BA6E-85F5DE39883B} + FSharp.Editor + FSharp.Editor + False + False + + $(MDFrameworkVersion) + + win + true + --publicsign + ..\..\..\..\..\msbuild\MonoDevelop-Public.snk + --warnon:1182 + Program + true + $(MSBuildProjectDirectory)\..\..\..\build\bin\MonoDevelop.exe + $(MSBuildProjectDirectory)\..\..\..\build\bin + portable false - ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor + ..\..\..\..\..\build\AddIns\FSharp.Editor 3 - ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor\FSharp.Editor.XML + ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML false --warnon:11111182 --subsystemversion:6.00 --simpleresolution --nocopyfsharpcore - ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor - 4 - ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor\FSharp.Editor.XML - false - - - ..\..\..\..\monodevelop\main\build\AddIns\FSharp.Editor - false + ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML + + + + + + + - - - - - - + + + + + + + - - - - - @@ -68,7 +73,7 @@ - + @@ -79,13 +84,13 @@ - - + + - + @@ -139,15 +144,15 @@ - + - - + + @@ -165,6 +170,8 @@ + + @@ -173,47 +180,51 @@ PublicResXFileCodeGenerator FSharp.Editor.Designer.fs - - - - - - - - - - - - - - - - - - - - - - - - Common\LspExternalAccess.fs - - - - - + + + {3F5B5BDA-69D5-441A-8142-AA25C998A997} + MonoDevelop.TextEditor + + + + + - - - - - - - - - - - - + + + + + + + + + + {7525BB88-6142-4A26-93B9-A30C6983390A} + MonoDevelop.Core + + + {27096E7F-C91C-4AC6-B289-6897A701DF21} + MonoDevelop.Ide + + + {4C10F8F9-3816-4647-BA6E-85F5DE39883A} + MonoDevelop.FSharp + + + {91DD5A2D-9FE3-4C3C-9253-876141874DAD} + Mono.Addins + + + + + + + + + + + + + From f5b9cb2153b8781de3606edf6b33bfb93e6f4d32 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 17 Feb 2020 11:33:26 +0000 Subject: [PATCH 020/101] Fix signing key --- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 034c7d206b4..cb1595ec26a 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -20,9 +20,7 @@ $(MDFrameworkVersion) win - true - --publicsign - ..\..\..\..\..\msbuild\MonoDevelop-Public.snk + --warnon:1182 Program true @@ -36,6 +34,9 @@ ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML false --warnon:11111182 --subsystemversion:6.00 --simpleresolution --nocopyfsharpcore + true + --publicsign + ..\..\..\src\buildtools\keys\MSFT.snk ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML From 7393def5743cbd95011496ebf2150317c4691187 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 17 Feb 2020 14:02:22 +0000 Subject: [PATCH 021/101] Add shared project to FSharp.Editor.fsproj --- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index cb1595ec26a..d1f6a5959b0 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -215,6 +215,10 @@ {91DD5A2D-9FE3-4C3C-9253-876141874DAD} Mono.Addins + + {AF5FEAD5-B50E-4F07-A274-32F23D5C504D} + MonoDevelop.FSharp.Shared + From 428234ea1a8e34e3f737f3e0e7f21ffbc25a8f94 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 17 Feb 2020 14:35:39 +0000 Subject: [PATCH 022/101] Add temporary references --- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index d1f6a5959b0..3062ee177cd 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -57,6 +57,15 @@ + + + False + $(RootDirectory)\build\bin\Xwt.dll + + + False + $(RootDirectory)\build\bin\Xwt.Gtk.dll + From 8de09b1047b3fceda1c9e8a150fc4248f7d3f460 Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 18 Feb 2020 14:45:15 +0000 Subject: [PATCH 023/101] Remove dependency on FSharpBinding --- .../{Project => Common}/CompilerArguments.fs | 21 +- .../Common/CompilerLocationUtils.fs | 423 +++++++++++ .../FSharp.Editor/Common/CompilerService.fs | 183 +++++ .../src/FSharp.Editor/Common/Extensions.fs | 11 + .../{Project => Common}/FSharpProject.fs | 37 +- .../src/FSharp.Editor/Common/FileService.fs | 88 +++ .../FSharp.Editor/Common/LanguageService.fs | 705 ++++++++++++++++++ .../FSharp.Editor/Common/MDLanguageService.fs | 173 +++++ .../Common/OrderAssemblyReferences.fs | 113 +++ .../src/FSharp.Editor/Common/Parameters.fs | 88 +++ .../src/FSharp.Editor/FSharp.Editor.fsproj | 53 +- .../FSharpProjectOptionsManager.fs | 7 +- 12 files changed, 1837 insertions(+), 65 deletions(-) rename vsintegration/src/FSharp.Editor/{Project => Common}/CompilerArguments.fs (95%) create mode 100644 vsintegration/src/FSharp.Editor/Common/CompilerLocationUtils.fs create mode 100644 vsintegration/src/FSharp.Editor/Common/CompilerService.fs rename vsintegration/src/FSharp.Editor/{Project => Common}/FSharpProject.fs (91%) create mode 100644 vsintegration/src/FSharp.Editor/Common/FileService.fs create mode 100644 vsintegration/src/FSharp.Editor/Common/LanguageService.fs create mode 100644 vsintegration/src/FSharp.Editor/Common/MDLanguageService.fs create mode 100644 vsintegration/src/FSharp.Editor/Common/OrderAssemblyReferences.fs create mode 100644 vsintegration/src/FSharp.Editor/Common/Parameters.fs diff --git a/vsintegration/src/FSharp.Editor/Project/CompilerArguments.fs b/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs similarity index 95% rename from vsintegration/src/FSharp.Editor/Project/CompilerArguments.fs rename to vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs index 94ba6163c19..416b2bbb590 100644 --- a/vsintegration/src/FSharp.Editor/Project/CompilerArguments.fs +++ b/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs @@ -13,10 +13,10 @@ open MonoDevelop.Projects open MonoDevelop.Ide open MonoDevelop.Core.Assemblies open MonoDevelop.Core -open ExtCore -open ExtCore.Control +//open ExtCore +//open ExtCore.Control open FSharp.Compiler.SourceCodeServices - +open Microsoft.VisualStudio.FSharp.Editor.Pervasive // -------------------------------------------------------------------------------------- // Common utilities for working with files & extracting information from // MonoDevelop objects (e.g. references, project items etc.) @@ -334,7 +334,7 @@ module CompilerArguments = else yield! ["COMPILED";"EDITING"] let configuration = - match IdeApp.Workspace |> Option.ofNull, project |> Option.ofNull with + match IdeApp.Workspace |> Option.ofObj, project |> Option.ofObj with | None, Some proj -> //as there is no workspace use the default configuration for the project Some (proj.GetConfiguration(proj.DefaultConfiguration.Selector)) @@ -355,11 +355,14 @@ module CompilerArguments = | _ -> MonoDevelop.Projects.ConfigurationSelector.Default let getArgumentsFromProject (proj:DotNetProject) (config:ConfigurationSelector) (referencedAssemblies) = - maybe { - let! projConfig = proj.GetConfiguration(config) |> Option.tryCast - let! fsconfig = projConfig.CompilationParameters |> Option.tryCast - return generateProjectOptions (proj, referencedAssemblies, fsconfig, None, getTargetFramework projConfig.TargetFramework.Id, config, false) - } + let projConfig = proj.GetConfiguration(config) :?> DotNetProjectConfiguration + let fsconfig = projConfig.CompilationParameters :?> FSharpCompilerParameters + generateProjectOptions (proj, referencedAssemblies, fsconfig, None, getTargetFramework projConfig.TargetFramework.Id, config, false) + //maybe { + // let! projConfig = proj.GetConfiguration(config) |> Option.tryCast + // let! fsconfig = projConfig.CompilationParameters |> Option.tryCast + // return generateProjectOptions (proj, referencedAssemblies, fsconfig, None, getTargetFramework projConfig.TargetFramework.Id, config, false) + //} let getReferencesFromProject (proj:DotNetProject, config:ConfigurationSelector, referencedAssemblies) = let projConfig = proj.GetConfiguration(config) :?> DotNetProjectConfiguration diff --git a/vsintegration/src/FSharp.Editor/Common/CompilerLocationUtils.fs b/vsintegration/src/FSharp.Editor/Common/CompilerLocationUtils.fs new file mode 100644 index 00000000000..9ea5a3a9745 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Common/CompilerLocationUtils.fs @@ -0,0 +1,423 @@ +namespace MonoDevelop.FSharp + +open System +open System.IO +open System.Configuration +open System.Reflection +open System.Runtime.InteropServices +open System.Text.RegularExpressions +open MonoDevelop.Core + +#nowarn "44" // ConfigurationSettings is obsolete but the new stuff is horribly complicated. + +module Environment = + /// Are we running on the Mono platform? + let runningOnMono = + try System.Type.GetType("Mono.Runtime") <> null + with _ -> false + + let getMonoPath() = + if File.Exists "/Library/Frameworks/Mono.framework/Commands/mono" then + "/Library/Frameworks/Mono.framework/Commands/mono" + else + "mono" + +/// Target framework (used to find the right version of F# binaries) +type FSharpTargetFramework = + | NET_2_0 + | NET_3_0 + | NET_3_5 + | NET_4_0 + | NET_4_5 + | NET_4_5_1 + | NET_4_5_2 + | NET_4_6 + | NET_4_6_1 + | NET_4_6_2 + | NET_4_7 + +type FSharpCompilerVersion = + // F# 2.0 + | FSharp_2_0 + // F# 3.0 + | FSharp_3_0 + // F# 3.1 + | FSharp_3_1 + override x.ToString() = match x with | FSharp_2_0 -> "4.0.0.0" | FSharp_3_0 -> "4.3.0.0" | FSharp_3_1 -> "4.3.1.0" + /// The current requested language version can be overriden by the user using environment variable. + static member LatestKnown = + match System.Environment.GetEnvironmentVariable("FSHARP_PREFERRED_VERSION") with + | null -> FSharp_3_1 + | "4.0.0.0" -> FSharp_2_0 + | "4.3.0.0" -> FSharp_3_0 + | "4.3.1.0" -> FSharp_3_1 + | _ -> FSharp_3_1 + +module FSharpEnvironment = + + let fsharpVers = [ FSharp_3_1; FSharp_3_0; FSharp_2_0 ] + + let safeExists f = (try File.Exists(f) with _ -> false) + + let FSharpCoreLibRunningVersion = + try + match (typeof>).Assembly.GetName().Version.ToString() with + | null -> None + | "" -> None + | s -> Some(s) + with _ -> None + + // Returns: + // -- on 2.0: "v2.0.50727" + // -- on 4.0: "v4.0.30109" (last 5 digits vary by build) + let MSCorLibRunningRuntimeVersion = + typeof.Assembly.ImageRuntimeVersion + + // The F# team version number. This version number is used for + // - the F# version number reported by the fsc.exe and fsi.exe banners in the CTP release + // - the F# version number printed in the HTML documentation generator + // - the .NET DLL version number for all VS2008 DLLs + // - the VS2008 registry key, written by the VS2008 installer + // HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework\AssemblyFolders\Microsoft.FSharp-" + FSharpTeamVersionNumber + // Also for Beta2, the language revision number indicated on the F# language spec + // + // It is NOT the version number listed on FSharp.Core.dll + let FSharpTeamVersionNumber = "2.0.0.0" + + // The F# binary format revision number. The first three digits of this form the significant part of the + // format revision number for F# binary signature and optimization metadata. The last digit is not significant. + // + // WARNING: Do not change this revision number unless you absolutely know what you're doing. + let FSharpBinaryMetadataFormatRevision = "2.0.0.0" + + [] + extern uint32 RegOpenKeyExW(UIntPtr _hKey, string _lpSubKey, uint32 _ulOptions, int _samDesired, UIntPtr & _phkResult); + + [] + extern uint32 RegQueryValueExW(UIntPtr _hKey, string _lpValueName, uint32 _lpReserved, uint32 & _lpType, IntPtr _lpData, int & _lpchData); + + [] + extern uint32 RegCloseKey(UIntPtr _hKey) + + // MaxPath accounts for the null-terminating character, for example, the maximum path on the D drive is "D:\<256 chars>\0". + // See: ndp\clr\src\BCL\System\IO\Path.cs + let maxPath = 260 + let maxDataLength = (new System.Text.UTF32Encoding()).GetMaxByteCount(maxPath) + let KEY_WOW64_DEFAULT = 0x0000 + let KEY_WOW64_32KEY = 0x0200 + let HKEY_LOCAL_MACHINE = UIntPtr(0x80000002u) + let KEY_QUERY_VALUE = 0x1 + let REG_SZ = 1u + + //let GetDefaultRegistryStringValueViaDotNet(subKey: string) = + //Option.ofString + //(try + // downcast Microsoft.Win32.Registry.GetValue("HKEY_LOCAL_MACHINE\\"+subKey,null,null) + //with e-> + //System.Diagnostics.Debug.Assert(false, sprintf "Failed in GetDefaultRegistryStringValueViaDotNet: %s" (e.ToString())) + //null) + + //let Get32BitRegistryStringValueViaPInvoke(subKey:string) = + //Option.ofString + //(try + // // 64 bit flag is not available <= Win2k + // let options = + // match Environment.OSVersion.Version.Major with + // | major when major >= 5 -> KEY_WOW64_32KEY + // | _ -> KEY_WOW64_DEFAULT + + + // let mutable hkey = UIntPtr.Zero; + // let pathResult = Marshal.AllocCoTaskMem(maxDataLength); + + // try + // let res = RegOpenKeyExW(HKEY_LOCAL_MACHINE,subKey, 0u, KEY_QUERY_VALUE ||| options, & hkey) + // if res = 0u then + // let mutable uType = REG_SZ; + // let mutable cbData = maxDataLength; + + // let res = RegQueryValueExW(hkey, null, 0u, &uType, pathResult, &cbData); + + // if (res = 0u && cbData > 0 && cbData <= maxDataLength) then + // Marshal.PtrToStringUni(pathResult, (cbData - 2)/2); + // else + // null + // else + // null + // finally + // if hkey <> UIntPtr.Zero then + // RegCloseKey(hkey) |> ignore + + // if pathResult <> IntPtr.Zero then + // Marshal.FreeCoTaskMem(pathResult) + //with e-> + //System.Diagnostics.Debug.Assert(false, sprintf "Failed in Get32BitRegistryStringValueViaPInvoke: %s" (e.ToString())) + //null) + +// let is32Bit = IntPtr.Size = 4 + +// let tryRegKey(subKey:string) = + +// if is32Bit then +// let s = GetDefaultRegistryStringValueViaDotNet(subKey) +// // If we got here AND we're on a 32-bit OS then we can validate that Get32BitRegistryStringValueViaPInvoke(...) works +// // by comparing against the result from GetDefaultRegistryStringValueViaDotNet(...) +//#if DEBUG +// let viaPinvoke = Get32BitRegistryStringValueViaPInvoke(subKey) +// System.Diagnostics.Debug.Assert((s = viaPinvoke), sprintf "32bit path: pi=%A def=%A" viaPinvoke s) +//#endif + // s + //else + //Get32BitRegistryStringValueViaPInvoke(subKey) + + let internal tryCurrentDomain() = + let pathFromCurrentDomain = System.AppDomain.CurrentDomain.BaseDirectory + if not(String.IsNullOrEmpty(pathFromCurrentDomain)) then + Some pathFromCurrentDomain + else + None + + let internal tryAppConfig (appConfigKey:string) = + + let locationFromAppConfig = ConfigurationSettings.AppSettings.[appConfigKey] + System.Diagnostics.Debug.Print(sprintf "Considering appConfigKey %s which has value '%s'" appConfigKey locationFromAppConfig) + + if String.IsNullOrEmpty(locationFromAppConfig) then + None + else + let exeAssemblyFolder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + let locationFromAppConfig = locationFromAppConfig.Replace("{exepath}", exeAssemblyFolder) + System.Diagnostics.Debug.Print(sprintf "Using path %s" locationFromAppConfig) + Some locationFromAppConfig + + /// Try to find the F# compiler location by looking at the "fsharpi" script installed by F# packages + let internal tryFsharpiScript(url:string) = + try + let str = File.ReadAllText(url) + let reg = new Regex("mono.* (\/.*)\/fsi\.exe") + let res = reg.Match(str) + if res.Success then Some(res.Groups.[1].Value) else None + with e -> + None + + let BackupInstallationProbePoints = + [ // prefer the latest installation of Mono on Mac + "/Library/Frameworks/Mono.framework/Versions/Current" + // prefer freshly built F# compilers on Linux + "/usr/local" + // otherwise look in the standard place + "/usr" ] + + //let tryWindowsConfig (reqLangVersion: FSharpCompilerVersion) = + ////early termination on Mono, continuing here results in failed pinvokes and reg key failures ~18-35ms + //if Environment.runningOnMono then None else + //// On windows the location of the compiler is via a registry key + //let key20 = @"Software\Microsoft\.NETFramework\AssemblyFolders\Microsoft.FSharp-" + FSharpTeamVersionNumber + //let key40 = match reqLangVersion with + // | FSharp_2_0 -> @"Software\Microsoft\FSharp\2.0\Runtime\v4.0" + // | FSharp_3_0 -> @"Software\Microsoft\FSharp\3.0\Runtime\v4.0" + // | FSharp_3_1 -> @"Software\Microsoft\FSharp\3.1\Runtime\v4.0" + + //let key1,key2 = match FSharpCoreLibRunningVersion with + // | None -> key20,key40 + // | Some v -> if v.Length > 1 && v.[0] <= '3' then key20,key40 + // else key40,key20 + + //LoggingService.LogDebug(sprintf "BinFolderOfDefaultFSharpCore: Probing registry key %s" key1) + //let result = tryRegKey key1 + //match result with + //| Some _ -> result + //| None -> LoggingService.LogDebug(sprintf "Resolution: BinFolderOfDefaultFSharpCore: Probing registry key %s" key2) + //tryRegKey key2 + + let tryUnixConfig() = + // On Unix we let you set FSHARP_COMILER_BIN. I've rarely seen this used and its not documented in the install isntructions. + LoggingService.LogDebug(sprintf "Resolution: BinFolderOfDefaultFSharpCore: Probing environment variable FSHARP_COMPILER_BIN") + let result = + let var = System.Environment.GetEnvironmentVariable("FSHARP_COMPILER_BIN") + if String.IsNullOrEmpty(var) then None + else Some(var) + + match result with + | Some _ -> result + | None -> + + // On Unix we probe 'bin' under various hardwired paths for the scripts 'fsharpc' and 'fsharpi'. + // We then loko in the script to see the Mono location it is pointing to. + // This is pretty fragile, e.g. the script lookup is done via a regular expression. + // Really we should just search the path or otherwise resolve the 'mono' command? + BackupInstallationProbePoints + |> List.tryPick (fun x -> + LoggingService.LogDebug(sprintf "Resolution: BinFolderOfDefaultFSharpCore: Probing %s" x) + let file f = Path.Combine(Path.Combine(x,"bin"),f) + let exists f = safeExists(file f) + match (if exists "fsc" && exists "fsi" then tryFsharpiScript (file "fsi") else None) with + | Some res -> Some res + | None -> if exists "fsharpc" && exists "fsharpi" then tryFsharpiScript (file "fsharpi") + else None) + + + // The default location of FSharp.Core.dll and fsc.exe based on the version of fsc.exe that is running + // Used for + // - location of design-time copies of FSharp.Core.dll and FSharp.Compiler.Interactive.Settings.dll for the default assumed environment for scripts + // - default ToolPath in tasks in FSharp.Build.dll (for Fsc tasks) + // - default F# binaries directory in service.fs (REVIEW: check this) + // - default location of fsi.exe in FSharp.VS.FSI.dll + // - default location of fsc.exe in FSharp.Compiler.CodeDom.dll + let BinFolderOfDefaultFSharpCompiler(reqLangVersion: Option) = + + let getBinFolder(reqLangVersion: FSharpCompilerVersion) = + // Check for an app.config setting to redirect the default compiler location + // Like fsharp-compiler-location + try + // FSharp.Compiler support setting an appkey for compiler location. I've never seen this used. + LoggingService.LogDebug("Resolution:BinFolderOfDefaultFSharpCore: Probing app.config") + let result = tryAppConfig "fsharp-compiler-location" + match result with + | Some _ -> result + + + | None -> + let result = tryUnixConfig() + match result with + | Some _ -> result + | None -> None + //| None -> let result = tryWindowsConfig reqLangVersion + //match result with + //| Some _ -> result + //| None -> let result = tryUnixConfig() + //match result with + //| Some _ -> result + //| None -> None + with e -> + System.Diagnostics.Debug.Assert(false, "Error while determining default location of F# compiler") + LoggingService.LogDebug(sprintf "Resolution: BinFolderOfDefaultFSharpCore: error %s" (e.ToString())) + None + + match reqLangVersion with + | Some v -> getBinFolder v + | None -> List.tryPick getBinFolder fsharpVers + + let FolderOfDefaultFSharpCore(reqLangVersion:Option, targetFramework) = + + let getFolder reqLangVersion = + try + LoggingService.LogDebug(sprintf "Resolution: Determing folder of FSharp.Core for target framework '%A'" targetFramework) + let result = tryAppConfig "fsharp-core-location" + match result with + | Some _ -> result + //| None -> + + //// On Windows, look for the registry key giving the installation location of FSharp.Core.dll. + //// This only works for .NET 2.0 - 4.0. To target Silverlight or Portable you'll need to use a direct reference to + //// the right FSharp.Core.dll. + //let result = + // //early termination on Mono, continuing here results in failed pinvokes and reg key failures ~18-35ms + // if Environment.runningOnMono then None else + // match reqLangVersion, targetFramework with + // | FSharp_2_0, x when (x = NET_2_0 || x = NET_3_0 || x = NET_3_5) -> + // tryRegKey @"Software\Microsoft\.NETFramework\v2.0.50727\AssemblyFoldersEx\Microsoft Visual F# 4.0" + // | FSharp_2_0, _ -> + // tryRegKey @"Software\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\Microsoft Visual F# 4.0" + // | FSharp_3_0, x when (x = NET_2_0 || x = NET_3_0 || x = NET_3_5) -> + // tryRegKey @"Software\Microsoft\.NETFramework\v2.0.50727\AssemblyFoldersEx\F# 3.0 Core Assemblies" + // | FSharp_3_0, NET_4_0 -> + // tryRegKey @"Software\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\F# 3.0 Core Assemblies" + // | FSharp_3_0, NET_4_5 -> + // tryRegKey @"Software\Microsoft\.NETFramework\v4.5.50709\AssemblyFoldersEx\F# 3.0 Core Assemblies" + // | FSharp_3_1, NET_4_5 -> + // tryRegKey @"Software\Microsoft\.NETFramework\v4.5.50709\AssemblyFoldersEx\F# 3.1 Core Assemblies" + // | _ -> None + + //match result with + //| Some _ -> result + | None -> + LoggingService.LogDebug(sprintf "Resolution: FSharp.Core: looking in environment variable") + let result = + let var = System.Environment.GetEnvironmentVariable("FSHARP_CORE_LOCATION") + if String.IsNullOrEmpty(var) then None + else Some(var) + match result with + | Some _ -> result + | None -> + let possibleInstallationPoints = + Option.toList (BinFolderOfDefaultFSharpCompiler(Some reqLangVersion) |> Option.map Path.GetDirectoryName) @ + BackupInstallationProbePoints + LoggingService.LogDebug(sprintf "Resolution: targetFramework = %A" targetFramework) + let ext = + match targetFramework with + | NET_2_0 | NET_3_0 | NET_3_5 -> "2.0" + | NET_4_0 -> "4.0" + | NET_4_5 -> "4.5" + | NET_4_5_1 -> "4.5.1" + | NET_4_5_2 -> "4.5.2" + | NET_4_6 -> "4.6" + | NET_4_6_1 -> "4.6.1" + | NET_4_6_2 -> "4.6.2" + | NET_4_7 -> "4.7" + + let safeExists f = (try File.Exists(f) with _ -> false) + let result = + possibleInstallationPoints |> List.tryPick (fun possibleInstallationDir -> + LoggingService.LogDebug(sprintf "Resolution: Probing for %s/lib/mono/%s/FSharp.Core.dll" possibleInstallationDir ext) + let (++) s x = Path.Combine(s,x) + let candidate = possibleInstallationDir ++ "lib" ++ "mono" ++ ext + if safeExists (candidate ++ "FSharp.Core.dll") then + Some candidate + else + None) + + match result with + | Some _ -> result + | None -> + let result = + possibleInstallationPoints |> List.tryPick (fun possibleInstallationDir -> + + LoggingService.LogDebug(sprintf "Resolution: Probing %s/bin for fsc/fsi scripts or fsharpc/fsharpi scripts" possibleInstallationDir) + + let file f = Path.Combine(Path.Combine(possibleInstallationDir,"bin"),f) + let exists f = safeExists(file f) + match (if exists "fsc" && exists "fsi" then tryFsharpiScript (file "fsi") else None) with + | Some res -> Some res + | None -> + match (if exists "fsharpc" && exists "fsharpi" then tryFsharpiScript (file "fsharpi") else None) with + | Some res -> Some res + | None -> None) + + match result with + | Some _ -> result + | None -> None + + with e -> + System.Diagnostics.Debug.Assert(false, "Error while determining default location of F# compiler") + None + + match reqLangVersion with + | Some v -> getFolder v + | None -> List.tryPick getFolder fsharpVers + + /// Returns default directories to be used when searching for DLL files + let getDefaultDirectories(langVersion: Option<_>, fsTargetFramework) = + + let dir = + match langVersion with + | Some _ -> FolderOfDefaultFSharpCore(langVersion, fsTargetFramework) + | None -> List.tryPick (fun v -> FolderOfDefaultFSharpCore(Some v, fsTargetFramework)) fsharpVers + + // Return all known directories, get the location of the System DLLs + [ match dir with + | Some dir -> LoggingService.LogDebug(sprintf "Resolution: Using '%A' as the location of default FSharp.Core.dll" dir) + yield dir + | None -> LoggingService.LogDebug(sprintf "Resolution: Unable to find a default location for FSharp.Core.dll") + yield System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()] + + /// Resolve assembly in the specified list of directories + let rec resolveAssembly dirs asm = + match dirs with + | dir::dirs -> + let asmPath = Path.Combine(dir, asm) + let any = List.tryFind safeExists [ asmPath + ".dll" ] + match any with + | Some(file) -> Some(file) + | _ -> resolveAssembly dirs asm + | [] -> None diff --git a/vsintegration/src/FSharp.Editor/Common/CompilerService.fs b/vsintegration/src/FSharp.Editor/Common/CompilerService.fs new file mode 100644 index 00000000000..3d1702a89db --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Common/CompilerService.fs @@ -0,0 +1,183 @@ +// -------------------------------------------------------------------------------------- +// Compilation of projects - generates command line options for +// the compiler and parses compiler error messages +// -------------------------------------------------------------------------------------- + +namespace MonoDevelop.FSharp + +open System +open System.IO +open System.Diagnostics +open System.Text.RegularExpressions +open MonoDevelop.Core +open MonoDevelop.Core.Assemblies +open MonoDevelop.Projects +open MonoDevelop.Ide +open CompilerArguments +// -------------------------------------------------------------------------------------- + +/// Functions that implement compilation, parsing, etc.. +// +// NOTE: Only used when xbuild support is not enabled. When xbuild is enabled, the .targets file finds +// FSharp.Build.dll which finds the F# compiler and builds the compilation arguments. +module CompilerService = + /// Generate various command line arguments for the project + let private generateCmdArgs (config:DotNetProjectConfiguration, projReferencedAssemblies, regLangVersion, configSel) = + [ match config.CompileTarget with + | CompileTarget.Library -> yield "--target:library" + | CompileTarget.Module -> yield "--target:module" + | CompileTarget.WinExe -> yield "--target:winexe" + | (*CompileTarget.Exe*)_ -> yield "--target:exe" + + if config.SignAssembly then yield "--keyfile:" + CompilerArguments.wrapFile(config.AssemblyKeyFile.ToString()) + yield "--out:" + CompilerArguments.wrapFile (config.CompiledOutputName.ToString()) + + // Generate compiler options based on F# specific project settings + let fsconfig = config.CompilationParameters :?> FSharpCompilerParameters + + if not (String.IsNullOrEmpty fsconfig.DocumentationFile) then + let docFile = config.CompiledOutputName.ChangeExtension(".xml").ToString() + yield ("--doc:" + CompilerArguments.wrapFile docFile) + + let shouldWrap = true// The compiler argument paths should always be wrapped, since some paths (ie. on Windows) may contain spaces. + let proj = config.ParentItem + yield! CompilerArguments.generateCompilerOptions (proj, projReferencedAssemblies, fsconfig, regLangVersion, CompilerArguments.getTargetFramework config.TargetFramework.Id, configSel, shouldWrap) ] + + + let private regParseFsOutput = Regex(@"(?[^\(]*)\((?[0-9]*),(?[0-9]*)\):\s(?[^:]*)\s(?[^:]*):\s(?.*)", RegexOptions.Compiled); + let private regParseFsOutputNoNum = Regex(@"(?[^\(]*)\((?[0-9]*),(?[0-9]*)\):\s(?[^:]*)\s(?.*)", RegexOptions.Compiled); + let private regParseFsOutputNoLocation = Regex(@"(?[^:]*)\s(?[^:]*):\s(?.*)", RegexOptions.Compiled); + + /// Process a single message emitted by the F# compiler + let processMsg msg = + let m = + let t1 = regParseFsOutput.Match(msg) + if t1.Success then t1 else + let t2 = regParseFsOutputNoNum.Match(msg) + if t2.Success then t2 else + regParseFsOutputNoLocation.Match(msg) + let get (s:string) = match m.Groups.Item(s) with null -> None | v -> match v.Value with null | "" -> None | x -> Some x + if m.Success then + let errNo = match get "err" with None -> "" | Some v -> v + let file = match get "file" with None -> "unknown-file" | Some v -> v + let line = match get "line" with None -> 1 | Some v -> int32 v + let col = match get "col" with None -> 1 | Some v -> int32 v + let msg = match get "msg" with None -> "" | Some v -> v + let isError = match get "type" with None -> true | Some v -> (v <> "warning") + isError, (file, line, col, errNo, msg) + else + true, ("unknown-file", 0, 0, "0", msg) + + (* + processMsg "warning FS0075: The command-line option '--warnon' is for internal use only" + = (false,("unknown-file", 1, 1, "FS0075","The command-line option '--warnon' is for internal use only")) + + processMsg @"C:\test\a.fs(2,17): warning FS0025: Incomplete pattern matches on this expression. For example, the value '0' may indicate a case not covered by the pattern(s)." + = (false,(@"C:\test\a.fs", 2, 17, "FS0025","Incomplete pattern matches on this expression. For example, the value '0' may indicate a case not covered by the pattern(s).")) + + processMsg @"C:\test space\a.fs(2,15): error FS0001: The type 'float' does not match the type 'int'" + = (true,(@"C:\test space\a.fs", 2, 15, "FS0001","The type 'float' does not match the type 'int'")) + + processMsg "error FS0082: Could not resolve this reference. Could not locate the assembly \"foo.dll\". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors. (Code=MSB3245)" + = (true,("unknown-file", 1, 1, "FS0082","Could not resolve this reference. Could not locate the assembly \"foo.dll\". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors. (Code=MSB3245)")) + *) + + /// Run the F# compiler with the specified arguments (passed as a list) + /// and print the arguments to progress monitor (Output in MonoDevelop) + let compile (runtime:TargetRuntime) (framework:TargetFramework) (monitor:ProgressMonitor) projectDir argsList = + + // let nw x = if x = None then "None" else x.Value + // monitor.Log.WriteLine("Env compiler: " + nw (Common.getCompilerFromEnvironment runtime framework)) + // monitor.Log.WriteLine("Override compiler: " + PropertyService.Get("FSharpBinding.FscPath")) + // monitor.Log.WriteLine("DefaultDefault compiler: " + (nw Common.getDefaultFSharpCompiler)) + // monitor.Log.WriteLine("Runtime: " + runtime.Id) + // monitor.Log.WriteLine("Framework: " + framework.Id.ToString()) + // monitor.Log.WriteLine("Default Runtime:" + IdeApp.Preferences.DefaultTargetRuntime.Id); + // monitor.Log.WriteLine("Default Framework:" + (Common.getDefaultTargetFramework IdeApp.Preferences.DefaultTargetRuntime).Id.ToString()) + + let br = BuildResult() + + // Concatenate arguments & run + let fscPath = + match CompilerArguments.getCompilerFromEnvironment runtime framework with + | Some(result) -> Some(result) + | None -> + match PropertyService.Get("FSharpBinding.FscPath","") with + | result when result <> "" -> + if runtime.Id <> IdeApp.Preferences.DefaultTargetRuntime.Value.Id then + br.AddWarning("No compiler found for the selected runtime; using default compiler instead.") |> ignore + Some(result) + | _ -> + match CompilerArguments.getDefaultFSharpCompiler() with + | Some(result) -> + if runtime.Id <> IdeApp.Preferences.DefaultTargetRuntime.Value.Id then + br.AddWarning("No compiler found for the selected runtime; using default compiler instead.") |> ignore + Some(result) + | None -> + br.AddError("No compiler found; add a default compiler in the F# settings.") |> ignore + None + + let args = String.concat "\n" argsList + + if fscPath = None then + br.FailedBuildCount <- 1 + br + else + monitor.Log.WriteLine("{0} {1}", fscPath.Value, args) + let args = String.concat " " argsList + let startInfo = + new ProcessStartInfo + (FileName = fscPath.Value, UseShellExecute = false, Arguments = args, + RedirectStandardError = true, CreateNoWindow = true, WorkingDirectory = projectDir) + LoggingService.LogDebug ("Compiler: Compile using: {0} Arguments: {1}", fscPath.Value, args) + let p = Process.Start(startInfo) + + LoggingService.LogDebug ("Compiler: Reading output..." ) + // Read all output and fold multi-line + let lines = + [ let line = ref "" + while (line := p.StandardError.ReadLine(); !line <> null) do + LoggingService.LogDebug ("Compiler: OUTPUT: {0}", !line) + yield !line + yield "" ] + let messages = + lines + |> Seq.fold (fun (current, all) line -> + if line = "" then [], (List.rev current)::all + else line::current, all) ([], []) + |> snd |> List.rev + |> List.map (String.concat " ") + |> List.filter (fun s -> s.Trim().Length > 0) + + // Parse messages and build results + for msg in messages do + match processMsg msg with + | true, (f, l, c, n, m) -> br.AddError(f, l, c, n, m) |> ignore + | false, (f, l, c, n, m) -> br.AddWarning(f, l, c, n, m) |> ignore + + + LoggingService.LogDebug ("Compiler: Waiting for exit...") + p.WaitForExit() + LoggingService.LogDebug ("Compiler: Done with compilation" ) + br.CompilerOutput <- String.concat "\n" lines + br + + // ------------------------------------------------------------------------------------ + /// Compiles the specified F# project using the current configuration + let Compile(items, config:DotNetProjectConfiguration, projReferencedAssemblies, configSel, monitor) : BuildResult = + let runtime = config.TargetRuntime + let framework = config.TargetFramework + let root = Path.GetDirectoryName(config.ParentItem.FileName.FullPath.ToString()) + let args = + [ yield! [ "--noframework --nologo" ] + yield! generateCmdArgs(config, projReferencedAssemblies, None, configSel) + yield! CompilerArguments.generateOtherItems items + + // Generate source files + let files = items + |> CompilerArguments.getSourceFiles + |> List.map CompilerArguments.wrapFile + yield! files ] + + compile runtime framework monitor root args + diff --git a/vsintegration/src/FSharp.Editor/Common/Extensions.fs b/vsintegration/src/FSharp.Editor/Common/Extensions.fs index 894ef61b23b..d17dcfd79ba 100644 --- a/vsintegration/src/FSharp.Editor/Common/Extensions.fs +++ b/vsintegration/src/FSharp.Editor/Common/Extensions.fs @@ -11,10 +11,21 @@ open Microsoft.CodeAnalysis.Host open FSharp.Compiler.Text open FSharp.Compiler.Ast open FSharp.Compiler.SourceCodeServices +open MonoDevelop.Core type private FSharpGlyph = FSharp.Compiler.SourceCodeServices.FSharpGlyph type private FSharpRoslynGlyph = Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpGlyph +module LoggingService = + let inline private log f = Printf.kprintf f + + let inline private logWithThread f format = + log (log f "[UI - %b] %s" Runtime.IsMainThread) format + + let logDebug format = logWithThread LoggingService.LogDebug format + let logError format = logWithThread LoggingService.LogError format + let logInfo format = logWithThread LoggingService.LogInfo format + let logWarning format = logWithThread LoggingService.LogWarning format type Path with static member GetFullPathSafe path = diff --git a/vsintegration/src/FSharp.Editor/Project/FSharpProject.fs b/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs similarity index 91% rename from vsintegration/src/FSharp.Editor/Project/FSharpProject.fs rename to vsintegration/src/FSharp.Editor/Common/FSharpProject.fs index d6e238d71a8..390294dad5b 100644 --- a/vsintegration/src/FSharp.Editor/Project/FSharpProject.fs +++ b/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs @@ -10,7 +10,7 @@ open MonoDevelop.Projects.MSBuild open System.Xml open MonoDevelop.Core.Assemblies //open ExtCore.Control - +open Microsoft.VisualStudio.FSharp.Editor.Pervasive module Project = let FSharp3Import = "$(MSBuildExtensionsPath32)\\..\\Microsoft SDKs\\F#\\3.0\\Framework\\v4.0\\Microsoft.FSharp.Targets" let FSharpImport = @"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets" @@ -29,6 +29,7 @@ type FSharpProject() as self = inherit DotNetProject() do self.RoslynLanguageName <- Microsoft.CodeAnalysis.LanguageNames.FSharp + self.SupportsRoslyn <- true // Keep the platforms combo of CodeGenerationPanelWidget in sync with this list let supportedPlatforms = [| "anycpu"; "x86"; "x64"; "Itanium" |] @@ -109,7 +110,7 @@ type FSharpProject() as self = |> List.map snd let isParentDirectory folderName fileName = - if String.isEmpty folderName then + if String.IsNullOrEmpty folderName then true else let absoluteFolder = DirectoryInfo (absolutePath folderName) @@ -223,7 +224,7 @@ type FSharpProject() as self = maybe { //Fix pcl netcore and TargetFSharpCoreVersion - let! targetFrameworkProfile = x.TargetFramework.Id.Profile |> Option.ofString + let! targetFrameworkProfile = x.TargetFramework.Id.Profile |> Option.ofObj let! fsharpcoreversion, netcore = profileMap |> Map.tryFind targetFrameworkProfile do globalGroup.SetValue ("TargetFSharpCoreVersion", fsharpcoreversion, "", true) let targetProfile = if netcore then "netcore" else "mscorlib" @@ -274,27 +275,27 @@ type FSharpProject() as self = override x.OnFileAddedToProject(e) = base.OnFileAddedToProject(e) - if not self.Loading then MDLanguageService.invalidateFiles e + //if not self.Loading then MDLanguageService.invalidateFiles e override x.OnFileRemovedFromProject(e) = base.OnFileRemovedFromProject(e) - if not self.Loading then MDLanguageService.invalidateFiles e + //if not self.Loading then MDLanguageService.invalidateFiles e override x.OnFileRenamedInProject(e) = base.OnFileRenamedInProject(e) - if not self.Loading then MDLanguageService.invalidateFiles e + //if not self.Loading then MDLanguageService.invalidateFiles e override x.OnFilePropertyChangedInProject(e) = base.OnFilePropertyChangedInProject(e) - if not self.Loading then MDLanguageService.invalidateFiles e + //if not self.Loading then MDLanguageService.invalidateFiles e override x.OnReferenceAddedToProject(e) = base.OnReferenceAddedToProject(e) - if not self.Loading then MDLanguageService.invalidateProjectFile self.FileName + //if not self.Loading then MDLanguageService.invalidateProjectFile self.FileName override x.OnReferenceRemovedFromProject(e) = base.OnReferenceRemovedFromProject(e) - if not self.Loading then MDLanguageService.invalidateProjectFile self.FileName + //if not self.Loading then MDLanguageService.invalidateProjectFile self.FileName //override x.OnFileRenamedInProject(e)= // base.OnFileRenamedInProject(e) @@ -302,25 +303,25 @@ type FSharpProject() as self = override x.OnNameChanged(e)= base.OnNameChanged(e) - if not self.Loading then MDLanguageService.invalidateProjectFile self.FileName + //if not self.Loading then MDLanguageService.invalidateProjectFile self.FileName override x.OnGetDefaultResourceId(projectFile) = projectFile.FilePath.FileName override x.OnModified(e) = base.OnModified(e) - if not self.Loading && not self.IsReevaluating then MDLanguageService.invalidateProjectFile self.FileName + //if not self.Loading && not self.IsReevaluating then MDLanguageService.invalidateProjectFile self.FileName member x.GetOrderedReferences(config:ConfigurationSelector) = async { let orderAssemblyReferences = MonoDevelop.FSharp.OrderAssemblyReferences() - let! asms = x.GetReferences config + let! asms = x.GetReferences config |> Async.AwaitTask let references = CompilerArguments.getReferencesFromProject (x, config, asms) |> Seq.choose (fun ref -> if (ref.Contains "mscorlib.dll" || ref.Contains "FSharp.Core.dll") then None else - let ref = ref |> String.replace "-r:" "" + let ref = ref.Replace ("-r:", "") if File.Exists ref then Some ref else None ) |> Seq.distinct @@ -332,15 +333,15 @@ type FSharpProject() as self = let task = base.OnReevaluateProject (e) async { - do! task - MDLanguageService.invalidateProjectFile self.FileName + do! task |> Async.AwaitTask + //MDLanguageService.invalidateProjectFile self.FileName } - override x.OnReevaluateProject(monitor) = - x.ReevaluateProject monitor |> StartAsyncAsTask monitor.CancellationToken :> Task + //override x.OnReevaluateProject(monitor) = + //x.ReevaluateProject monitor |> Async.AwaitTask monitor.CancellationToken :> Task override x.OnDispose () = - languageService.HideStatusIcon (string self.FileName.FullPath) + //languageService.HideStatusIcon (string self.FileName.FullPath) // FIXME: is it correct to do it every time a project is disposed? //Should only be done on solution close //langServ.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() diff --git a/vsintegration/src/FSharp.Editor/Common/FileService.fs b/vsintegration/src/FSharp.Editor/Common/FileService.fs new file mode 100644 index 00000000000..b526aac027f --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Common/FileService.fs @@ -0,0 +1,88 @@ +namespace MonoDevelop.FSharp +open FSharp.Compiler.AbstractIL.Internal.Library +open System.IO +open MonoDevelop.Ide +open MonoDevelop.Ide.Gui +open MonoDevelop.Core +//open ExtCore.Control +type Version = int + +type FileSystem (defaultFileSystem : IFileSystem, openDocuments: unit -> Document seq) = + let timestamps = new System.Collections.Generic.Dictionary() + let getOpenDoc filename = + let docs = openDocuments() + docs |> Seq.tryFind(fun d -> d.FileName.FullPath.ToString() = filename) + + let getOpenDocContent (filename: string) = + match getOpenDoc filename with + | Some d -> + match d.Editor with + | null -> None + | editor -> + let bytes = System.Text.Encoding.UTF8.GetBytes (editor.Text) + Some bytes + | _ -> None + + static member IsAScript fileName = + let ext = Path.GetExtension fileName + [".fsx";".fsscript";".sketchfs"] |> List.exists ((=) ext) + + //interface IFileSystem with + //member x.FileStreamReadShim fileName = + // getOpenDocContent fileName + // |> Option.map (fun bytes -> new MemoryStream (bytes) :> Stream) + // |> Option.orElse (fun () -> defaultFileSystem.FileStreamReadShim fileName) + + //member x.ReadAllBytesShim fileName = + // getOpenDocContent fileName + // |> Option.getOrElse (fun () -> defaultFileSystem.ReadAllBytesShim fileName) + + //member x.GetLastWriteTimeShim fileName = defaultFileSystem.GetLastWriteTimeShim(fileName) + // //let r = maybe { + // // let! doc = getOpenDoc fileName + // // if doc.IsDirty then + // // let key, newhash = fileName, doc.Editor.Text.GetHashCode() + // // return match timestamps.TryGetValue (key) with + // // | true, (hash, date) when hash = newhash -> date + // // | _ -> let d = System.DateTime.Now + // // timestamps.[key] <- (newhash,d) + // // d + // // else return! None + // // } + // //r |> Option.getOrElse (fun () -> defaultFileSystem.GetLastWriteTimeShim fileName) + + //member x.GetTempPathShim() = defaultFileSystem.GetTempPathShim() + //member x.FileStreamCreateShim fileName = defaultFileSystem.FileStreamCreateShim fileName + //member x.FileStreamWriteExistingShim fileName = defaultFileSystem.FileStreamWriteExistingShim fileName + //member x.GetFullPathShim fileName = defaultFileSystem.GetFullPathShim fileName + //member x.IsInvalidPathShim fileName = defaultFileSystem.IsInvalidPathShim fileName + //member x.IsPathRootedShim fileName = defaultFileSystem.IsPathRootedShim fileName + //member x.SafeExists fileName = defaultFileSystem.SafeExists fileName + //member x.FileDelete fileName = defaultFileSystem.FileDelete fileName + //member x.AssemblyLoadFrom fileName = defaultFileSystem.AssemblyLoadFrom fileName + //member x.AssemblyLoad(assemblyName) = defaultFileSystem.AssemblyLoad assemblyName + //member x.IsStableFileHeuristic _fileName = true + +module FileService = + let supportedFileExtensions = + set [".fsscript"; ".fs"; ".fsx"; ".fsi"; ".sketchfs"] + + /// Is the specified extension supported F# file? + let supportedFileName fileName = + if fileName = null then + false + else + let ext = Path.GetExtension(fileName).ToLower() + supportedFileExtensions + |> Set.contains ext + + let isInsideFSharpFile () = + if IdeApp.Workbench.ActiveDocument = null || + IdeApp.Workbench.ActiveDocument.FileName.FileName = null then false + else + let file = IdeApp.Workbench.ActiveDocument.FileName.ToString() + supportedFileName (file) + + let supportedFilePath (filePath:FilePath) = + supportedFileName (string filePath) + diff --git a/vsintegration/src/FSharp.Editor/Common/LanguageService.fs b/vsintegration/src/FSharp.Editor/Common/LanguageService.fs new file mode 100644 index 00000000000..10ad0372da8 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Common/LanguageService.fs @@ -0,0 +1,705 @@ +namespace MonoDevelop.FSharp +open System +open System.Collections.Generic +open System.IO +open System.Diagnostics +open FSharp.Compiler +open FSharp.Compiler.SourceCodeServices +open FSharp.Compiler.Text +open MonoDevelop.FSharp +open MonoDevelop.Core +open MonoDevelop.Ide +open MonoDevelop.Ide.TypeSystem +open MonoDevelop.Projects +//type LoggingService = MonoDevelop.FSharp.LoggingService +open Microsoft.VisualStudio.FSharp.Editor.Extensions + +module Symbol = + /// We always know the text of the identifier that resolved to symbol. + /// Trim the range of the referring text to only include this identifier. + /// This means references like A.B.C are trimmed to "C". This allows renaming to just rename "C". + let trimSymbolRegion(symbolUse:FSharpSymbolUse) (lastIdentAtLoc:string) = + let m = symbolUse.RangeAlternate + let ((beginLine, beginCol), (endLine, endCol)) = ((m.StartLine, m.StartColumn), (m.EndLine, m.EndColumn)) + + let (beginLine, beginCol) = + if endCol >=lastIdentAtLoc.Length && (beginLine <> endLine || (endCol-beginCol) >= lastIdentAtLoc.Length) then + (endLine,endCol-lastIdentAtLoc.Length) + else + (beginLine, beginCol) + Range.mkPos beginLine beginCol, Range.mkPos endLine endCol + //(beginLine, beginCol), (endLine, endCol) + +/// Contains settings of the F# language service +module ServiceSettings = + let internal getEnvInteger e dflt = match System.Environment.GetEnvironmentVariable(e) with null -> dflt | t -> try int t with _ -> dflt + /// When making blocking calls from the GUI, we specify this value as the timeout, so that the GUI is not blocked forever + let blockingTimeout = getEnvInteger "FSharpBinding_BlockingTimeout" 1000 + let maximumTimeout = getEnvInteger "FSharpBinding_MaxTimeout" 10000 + let idleBackgroundCheckTime = getEnvInteger "FSharpBinding_IdleBackgroundCheckTime" 2000 + +// -------------------------------------------------------------------------------------- +/// Wraps the result of type-checking and provides methods for implementing +/// various IntelliSense functions (such as completion & tool tips). +/// Provides default empty/negative results if information is missing. +//type ParseAndCheckResults (infoOpt : FSharpCheckFileResults option, parseResults : FSharpParseFileResults option) = + + ///// Get the symbols for declarations at the current location in the specified document and the long ident residue + ///// e.g. The incomplete ident One.Two.Th will return Th + //member x.GetDeclarationSymbols(line, col, lineStr) = + // async { + // match infoOpt, parseResults with + // | Some checkResults, parseResults -> + // // Get items & generate output + // let partialName = QuickParse.GetPartialLongNameEx(lineStr, col-1) + + // try + // let! results = checkResults.GetDeclarationListSymbols(parseResults, line, lineStr, partialName) + + // return Some (results, partialName.PartialIdent) + // with :? TimeoutException -> return None + // | None, _ -> return None + // } + + /////// Get the tool-tip to be displayed at the specified offset (relatively + /////// from the beginning of the current document) + ////member x.GetToolTip(line, col, lineStr) = + //// async { + //// match infoOpt with + //// | Some checkResults -> + //// match MonoDevelop.FSharp.Shared.Parsing.findIdents col lineStr MonoDevelop.FSharp.Shared.SymbolLookupKind.ByLongIdent with + //// | None -> return None + //// | Some(col,identIsland) -> + //// let! res = checkResults.GetToolTipText(line, col, lineStr, identIsland, FSharpTokenTag.Identifier) + //// return Some (res, line) + //// | None -> return None } + + ////member x.GetDeclarationLocation(line, col, lineStr) = + // //async { + // //match infoOpt with + // //| Some checkResults -> + // // match MonoDevelop.FSharp.Shared.Parsing.findIdents col lineStr MonoDevelop.FSharp.Shared.SymbolLookupKind.ByLongIdent with + // // | None -> return FSharpFindDeclResult.DeclNotFound (FSharpFindDeclFailureReason.Unknown "No idents found") + // // | Some(col,identIsland) -> return! checkResults.GetDeclarationLocation(line, col, lineStr, identIsland, false) + // //| None -> return FSharpFindDeclResult.DeclNotFound (FSharpFindDeclFailureReason.Unknown "No check results")} + + ////member x.GetSymbolAtLocation(line, col, lineStr) = + // //async { + // //match infoOpt with + // //| Some (checkResults) -> + // // match MonoDevelop.FSharp.Shared.Parsing.findIdents col lineStr MonoDevelop.FSharp.Shared.SymbolLookupKind.ByLongIdent + // // |> Option.orTry (fun () -> MonoDevelop.FSharp.Shared.Parsing.findIdents col lineStr MonoDevelop.FSharp.Shared.SymbolLookupKind.Fuzzy) with + // // | None -> return None + // // | Some(colu, identIsland) -> + // // try + // // let! symbolUse = checkResults.GetSymbolUseAtLocation(line, colu, lineStr, identIsland) + // // return symbolUse + // // with ex -> + // // LoggingService.LogDebug("Error at: GetSymbolUseAtLocation}", ex) + // // return None + // //| None -> return None } + + ////member x.GetMethodsAsSymbols(line, col, (lineStr:string)) = + // //async { + // //match infoOpt with + // //| Some checkResults -> + // // let lineToCaret = lineStr.[0..col-1] + // // let column = lineToCaret |> Seq.tryFindIndexBack (fun c -> c <> '(' && c <> ' ') + // // match column with + // // | Some col -> + // // match MonoDevelop.FSharp.Shared.Parsing.findIdents (col-1) lineToCaret MonoDevelop.FSharp.Shared.SymbolLookupKind.ByLongIdent with + // // | None -> return None + // // | Some(colu, identIsland) -> + // // return! checkResults.GetMethodsAsSymbols(line, colu, lineToCaret, identIsland) + // // | _ -> return None + // //| None -> return None } + + //member x.GetUsesOfSymbolInFile(symbol) = + // async { + // match infoOpt with + // | Some checkResults -> return! checkResults.GetUsesOfSymbolInFile(symbol) + // | None -> return [| |] } + + //member x.GetAllUsesOfAllSymbolsInFile() = + // async { + // match infoOpt with + // | Some checkResults -> + // let! allSymbols = checkResults.GetAllUsesOfAllSymbolsInFile() + // return Some allSymbols + // | None -> return None } + + //member x.PartialAssemblySignature = + // async { + // match infoOpt with + // | Some (checkResults) -> + // return Some checkResults.PartialAssemblySignature + // | None -> return None } + + //member x.GetErrors() = + // match infoOpt, parseResults with + // | Some checkResults, Some parseResults -> + // checkResults.Errors + // |> Array.append parseResults.Errors + // |> Seq.distinct + // | Some checkResults, None -> checkResults.Errors |> Array.toSeq + // | None, Some parseResults -> parseResults.Errors |> Array.toSeq + // | None, None -> Seq.empty + + //member x.GetNavigationItems() = + // match parseResults with + // | None -> [| |] + // | Some parseResults -> + // // GetNavigationItems is not 100% solid and throws occasional exceptions + // try parseResults.GetNavigationItems().Declarations + // with _ -> + // Debug.Assert(false, "couldn't update navigation items, ignoring") + // [| |] + + //member x.ParseTree = + // match parseResults with + // | Some parseResults -> parseResults.ParseTree + // | None -> None + + //member x.CheckResults = infoOpt + + //member x.GetExtraColorizations(range) = + // match infoOpt with + // | Some checkResults -> Some(checkResults.GetSemanticClassification(range)) + // | None -> None + + //member x.GetStringFormatterColours() = + // match infoOpt with + // | Some checkResults -> Some(checkResults.GetFormatSpecifierLocationsAndArity()) + // | None -> None + + ///// Get all the uses of a symbol in the given file + //member x.GetUsesOfSymbolAtLocationInFile(fileName, line, col, lineStr) = + //asyncMaybe { + // LoggingService.logDebug "LanguageService: GetUsesOfSymbolAtLocationInFile: file:%s, line:%i, col:%i" (Path.GetFileName(fileName)) line col + // let! colu, identIsland = MonoDevelop.FSharp.Shared.Parsing.findIdents col lineStr MonoDevelop.FSharp.Shared.SymbolLookupKind.ByLongIdent |> async.Return + // let! results = infoOpt |> async.Return + // let! symbolUse = results.GetSymbolUseAtLocation(line, colu, lineStr, identIsland) + // let! symbolUse = x.GetSymbolAtLocation(line, col, lineStr) + // let lastIdent = Seq.last identIsland + // let! refs = results.GetUsesOfSymbolInFile(symbolUse.Symbol) |> Async.map Some + // return (lastIdent, refs) + //} + +[] +type AllowStaleResults = + // Allow checker results where the source doesn't even match + | MatchingFileName + // Allow checker results where the source matches but where the background builder may not have caught up yet after some other change + | MatchingSource + +//type Debug = System.Console +open Microsoft.VisualStudio.FSharp.Editor.Pervasive + +/// Provides functionality for working with the F# interactive checker running in background +type LanguageService(dirtyNotify, _extraProjectInfo) as x = + + /// Load times used to reset type checking properly on script/project load/unload. It just has to be unique for each project load/reload. + /// Not yet sure if this works for scripts. + let fakeDateTimeRepresentingTimeLoaded proj = DateTime(abs (int64 (match proj with null -> 0 | _ -> proj.GetHashCode())) % 103231L) + let checkProjectResultsCache = Collections.Generic.Dictionary() + + //let projectChecked filename = + //let computation = + // async { + // let displayname = Path.GetFileName filename + // LoggingService.logDebug "LanguageService: Project checked: %s" displayname + // if checkProjectResultsCache.ContainsKey filename then + // LoggingService.logDebug "LanguageService: Removing project check results for: %s" displayname + // checkProjectResultsCache.Remove(filename) |> ignore + + // LoggingService.logDebug "LanguageService: Getting project checker options for: %s" displayname + // let projOptions = + // //if File.Exists filename then + // x.GetProjectCheckerOptions(filename) + // //else + // //let trimmedfilename = + // // let finaldot = filename.LastIndexOf "." + // // if finaldot > 0 then filename.[..finaldot-1] else "" + // //if not (String.IsNullOrWhiteSpace trimmedfilename) && File.Exists trimmedfilename then + // // let source = File.ReadAllText trimmedfilename + // // x.GetScriptCheckerOptions(filename, filename, source) + // //else + // //LoggingService.logDebug "LanguageService: Could not generate project options for: %s file does not exist" filename + // //None + // match projOptions with + // | Some projOptions -> + // LoggingService.logDebug "LanguageService: Getting CheckProjectResults for: %s" displayname + // try + // let! (projCheck:FSharpCheckProjectResults) = x.ParseAndCheckProject(projOptions) + // if not projCheck.HasCriticalErrors then + // LoggingService.logDebug "LanguageService: Adding CheckProjectResults to cache for: %s" displayname + // checkProjectResultsCache.Add(filename, projCheck) |> ignore + // else + // LoggingService.logDebug "LanguageService: NOT adding CheckProjectResults to cache for: %s due to critical errors" displayname + // with exn -> + // LoggingService.LogDebug(sprintf "LanguageService: Error", exn) + // | None -> () } + ////Async.StartAndLogException computation + //Async.Start computation + + let loadingProjects = HashSet() + + let showStatusIcon projectFileName = + () + //if loadingProjects.Add projectFileName then + //IdeApp.TypeSystemService.BeginWorkspaceLoad() + + let hideStatusIcon projectFileName = + () + //if loadingProjects.Remove projectFileName then + //IdeApp.TypeSystemService.EndWorkspaceLoad() + + // Create an instance of interactive checker. The callback is called by the F# compiler service + // when its view of the prior-typechecking-state of the start of a file has changed, for example + // when the background typechecker has "caught up" after some other file has been changed, + // and its time to re-typecheck the current file. +// let checker = +// let checker = FSharpChecker.Create() +// checker.PauseBeforeBackgroundWork <- ServiceSettings.idleBackgroundCheckTime +// checker.BeforeBackgroundFileCheck.Add dirtyNotify +//#if DEBUG +// checker.FileParsed.Add (fun (filename, _) -> LoggingService.logDebug "LanguageService: File parsed: %s" filename) +// checker.FileChecked.Add (fun (filename, _) -> LoggingService.logDebug "LanguageService: File type checked: %s" filename) +//#endif + //checker.ProjectChecked.Add (fun (filename, _) -> + // projectChecked filename + // hideStatusIcon filename) + //checker + + /// When creating new script file on Mac, the filename we get sometimes + /// has a name //foo.fsx, and as a result 'Path.GetFullPath' throws in the F# + /// language service - this fixes the issue by inventing nicer file name. + let fixFileName path = + if (try Path.GetFullPath(path) |> ignore; true + with _ -> false) then path + else + let dir = + if Environment.OSVersion.Platform = PlatformID.Unix || + Environment.OSVersion.Platform = PlatformID.MacOSX then + Environment.GetEnvironmentVariable("HOME") + else + Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%") + Path.Combine(dir, Path.GetFileName(path)) + + //let projectInfoCache = + ////cache 50 project infos, then start evicting the least recently used entries + //ref (ExtCore.Caching.LruCache.create 50u) + + let optionsForDependentProject projectFile = + let project = x.GetProjectFromFileName projectFile + async { + let! assemblies = async { + match project with + | Some (proj:DotNetProject) -> return! proj.GetReferences(CompilerArguments.getConfig()) |> Async.AwaitTask + | None -> return new List () + } + return x.GetProjectCheckerOptions(projectFile, [], assemblies) + } + + //member x.Checker = checker + + member x.HideStatusIcon = hideStatusIcon + + //member x.ClearProjectInfoCache() = + //LoggingService.logDebug "LanguageService: Clearing ProjectInfoCache" + //projectInfoCache := ExtCore.Caching.LruCache.create 50u + + /// Constructs options for the interactive checker for the given file in the project under the given configuration. + //member x.GetCheckerOptions(fileName, projFilename, source) = + //let opts = + // if FileSystem.IsAScript fileName || fileName = projFilename + // // We are in a stand-alone file or we are in a project, but currently editing a script file + // then x.GetScriptCheckerOptions(fileName, projFilename, source) + // // We are in a project - construct options using current properties + // else x.GetProjectCheckerOptions(projFilename) + //opts + + //member x.GetParsingOptionsFromProjectOptions(projectOptions) = + // checker.GetParsingOptionsFromProjectOptions projectOptions + + ///// Constructs options for the interactive checker for the given script file in the project under the given configuration. + //member x.GetScriptCheckerOptions(fileName, projFilename, source) = + //let opts = + // // We are in a stand-alone file or we are in a project, but currently editing a script file + // try + // let fileName = fixFileName(fileName) + // LoggingService.LogDebug ("LanguageService: GetScriptCheckerOptions: Creating for stand-alone file or script: {0}", fileName) + // let opts, _errors = + // Async.RunSynchronously (checker.GetProjectOptionsFromScript(fileName, SourceText.ofString source, fakeDateTimeRepresentingTimeLoaded projFilename), + // timeout = ServiceSettings.maximumTimeout) + + // // The InteractiveChecker resolution sometimes doesn't include FSharp.Core and other essential assemblies, so we need to include them by hand + // if opts.OtherOptions |> Seq.exists (fun s -> s.Contains("FSharp.Core.dll")) then opts + // else + // // Add assemblies that may be missing in the standard assembly resolution + // LoggingService.LogDebug("LanguageService: GetScriptCheckerOptions: Adding missing core assemblies.") + // let dirs = FSharpEnvironment.getDefaultDirectories (None, FSharpTargetFramework.NET_4_5 ) + // { opts with OtherOptions = [| yield! opts.OtherOptions + // match FSharpEnvironment.resolveAssembly dirs "FSharp.Core" with + // | Some fn -> yield String.Format ("-r:{0}", fn) + // | None -> + // LoggingService.LogDebug("LanguageService: Resolution: FSharp.Core assembly resolution failed!") + // match FSharpEnvironment.resolveAssembly dirs "FSharp.Compiler.Interactive.Settings" with + // | Some fn -> yield String.Format ("-r:{0}", fn) + // | None -> LoggingService.LogDebug("LanguageService: Resolution: FSharp.Compiler.Interactive.Settings assembly resolution failed!") |]} + // with e -> failwithf "Exception when getting check options for '%s'\n.Details: %A" fileName e + + //// Print contents of check option for debugging purposes + //// LoggingService.LogDebug(sprintf "GetScriptCheckerOptions: ProjectFileName: %s, ProjectFileNames: %A, ProjectOptions: %A, IsIncompleteTypeCheckEnvironment: %A, UseScriptResolutionRules: %A" + //// opts.ProjectFileName opts.ProjectFileNames opts.ProjectOptions opts.IsIncompleteTypeCheckEnvironment opts.UseScriptResolutionRules) + //Some opts + + member x.GetProjectFromFileName projectFile = + IdeApp.Workspace.GetAllProjects() + |> Seq.tryFind (fun p -> p.FileName.FullPath.ToString() = projectFile) + |> Option.map(fun p -> p :?> DotNetProject) + + //maybe { + // let! projConfig = proj.GetConfiguration(config) |> Option.tryCast + // let! fsconfig = projConfig.CompilationParameters |> Option.tryCast + // return generateProjectOptions (proj, referencedAssemblies, fsconfig, None, getTargetFramework projConfig.TargetFramework.Id, config, false) + //} + member x.GetProjectOptionsFromProjectFile (project:DotNetProject) (config:ConfigurationSelector) (referencedAssemblies:AssemblyReference seq) = + + // hack: we can't just pull the refs out of referencedAssemblies as we use this for referenced projects as well + let getReferencedFSharpProjects (project:DotNetProject) = + project.GetReferencedAssemblyProjects config + |> Seq.filter (fun p -> p <> project && p.SupportedLanguages |> Array.contains "F#") + + let rec getOptions referencedProject = + // hack: we use the referencedAssemblies of the root project for the dependencies' options as well + // which is obviously wrong, but it doesn't seem to matter in this case + let projectOptions = CompilerArguments.getArgumentsFromProject referencedProject config referencedAssemblies + //match projectOptions with + //| Some projOptions -> + let referencedProjectOptions = + referencedProject + |> getReferencedFSharpProjects + |> Seq.fold (fun acc reference -> + match getOptions reference with + | Some outFile, Some opts -> (outFile, opts) :: acc + | _ -> acc) ([]) + + (Some (referencedProject.GetOutputFileName(config).ToString()), Some ({ projectOptions with ReferencedProjects = referencedProjectOptions |> Array.ofList } )) + //| None -> None, None + let _file, projectOptions = getOptions project + projectOptions + + //member x.TryGetProjectCheckerOptionsFromCache(projFilename, ?properties) : FSharpProjectOptions option = + //let properties = defaultArg properties ["Configuration", IdeApp.Workspace.ActiveConfigurationId] + //let key = (projFilename, properties) + //let entry, _ = (!projectInfoCache).TryFind (key) + //entry + + /// Constructs options for the interactive checker for a project under the given configuration. + member x.GetProjectCheckerOptions(projFilename, ?properties, ?referencedAssemblies) : FSharpProjectOptions option = + let config = + maybe { + let! ws = IdeApp.Workspace |> Option.ofObj + return! ws.ActiveConfiguration |> Option.ofObj + } |> Option.defaultValue ConfigurationSelector.Default + let configId = + match IdeApp.Workspace with + | null -> null + | ws -> ws.ActiveConfigurationId + let properties = defaultArg properties ["Configuration", configId] + let key = (projFilename, properties) + + //lock projectInfoCache (fun () -> + //match (!projectInfoCache).TryFind (key) with + //| Some entry, cache -> + // LoggingService.logDebug "LanguageService: GetProjectCheckerOptions: Getting ProjectOptions from cache for:%s}" (Path.GetFileName(projFilename)) + // projectInfoCache := cache + // Some entry + //| _, cache -> + showStatusIcon projFilename + let project = + IdeApp.Workspace.GetAllProjects() + |> Seq.tryFind (fun p -> p.FileName.FullPath.ToString() = projFilename) + + match project with + | Some proj -> + let proj = proj :?> DotNetProject + //fixme eliminate this .Result + let asms = match referencedAssemblies with + | Some a -> a + | None -> (proj.GetReferences config).Result + let opts = x.GetProjectOptionsFromProjectFile proj config asms + opts |> Option.bind(fun opts' -> + //projectInfoCache := cache.Add (key, opts') + // Print contents of check option for debugging purposes + LoggingService.logDebug "GetProjectCheckerOptions: ProjectFileName: %s, ProjectFileNames: %A, ProjectOptions: %A, IsIncompleteTypeCheckEnvironment: %A, UseScriptResolutionRules: %A" + opts'.ProjectFileName opts'.SourceFiles opts'.OtherOptions opts'.IsIncompleteTypeCheckEnvironment opts'.UseScriptResolutionRules + opts) + | None -> None + + //member x.StartBackgroundCompileOfProject (projectFilename) = + //x.GetProjectCheckerOptions(projectFilename) + //|> Option.iter(fun opts -> checker.CheckProjectInBackground(opts)) + + //member internal x.TryGetStaleTypedParseResult(fileName:string, options, src, stale) = + // // Try to get recent results from the F# service + // let res = + // match stale with + // | AllowStaleResults.MatchingFileName -> checker.TryGetRecentCheckResultsForFile(fixFileName fileName, options) + // | AllowStaleResults.MatchingSource -> checker.TryGetRecentCheckResultsForFile(fixFileName fileName, options, sourceText = SourceText.ofString src) + + // match res with + // | Some (untyped,typed,_) when typed.HasFullTypeCheckInfo -> Some (ParseAndCheckResults(Some typed, Some untyped)) + // | Some (untyped,_,_) -> Some (ParseAndCheckResults(None, Some untyped)) + // | _ -> None + + //member internal x.ParseAndCheckFile (fileName, src, version:int, options: FSharpProjectOptions option, obsoleteCheck) = + // async { + // try + // let fileName = fixFileName(fileName) + // match options with + // | Some opts -> + // let! parseResults, checkAnswer = checker.ParseAndCheckFileInProject(fileName, version, src ,opts, obsoleteCheck) + + // // Construct new typed parse result if the task succeeded + // let results = + // match checkAnswer with + // | FSharpCheckFileAnswer.Succeeded(checkResults) -> + // LoggingService.logDebug "LanguageService: ParseAndCheckFile check succeeded for %s" (Path.GetFileName(fileName)) + // ParseAndCheckResults(Some checkResults, Some parseResults) + // | FSharpCheckFileAnswer.Aborted -> + // LoggingService.logDebug "LanguageService: ParseAndCheckFile check aborted for %s" (Path.GetFileName(fileName)) + // ParseAndCheckResults(None, Some parseResults) + + // return results + // | None -> return ParseAndCheckResults(None, None) + // with exn -> + // LoggingService.LogDebug("LanguageService agent: Exception", exn) + // return ParseAndCheckResults(None, None) } + + //member x.ParseAndCheckFileInProject(projectFilename, fileName, version:int, src:string, obsoleteCheck) = + // let fileName = if Path.GetExtension fileName = ".sketchfs" then Path.ChangeExtension (fileName, ".fsx") else fileName + // let opts = x.GetCheckerOptions(fileName, projectFilename, src) + // x.ParseAndCheckFile(fileName, SourceText.ofString src, version, opts, obsoleteCheck) + + ///// Parses and checks the given file in the given project under the given configuration. + /////Asynchronously returns the results of checking the file. + //member x.GetTypedParseResultWithTimeout(projectFilename, fileName, version:int, src:string, stale, ?timeout, ?obsoleteCheck) = + //let obs = defaultArg obsoleteCheck (fun () -> false) + //async { + //let fileName = if Path.GetExtension fileName = ".sketchfs" then Path.ChangeExtension (fileName, ".fsx") else fileName + //let options = x.GetCheckerOptions(fileName, projectFilename, src) + //match options with + //| Some opts -> + // // Try to get recent results from the F# service + // match x.TryGetStaleTypedParseResult(fileName, opts, src, stale) with + // | Some _ as results -> + // LoggingService.logDebug "LanguageService: GetTypedParseResultWithTimeout: using stale results" + // return results + // | None -> + // // If we didn't get a recent set of type checking results, we put in a request and wait for at most 'timeout' for a response + // match timeout with + // | Some timeout -> + // LoggingService.logDebug "LanguageService: GetTypedParseResultWithTimeout: No stale results - typechecking with timeout" + // let! computation = Async.StartChild(x.ParseAndCheckFile(fileName, SourceText.ofString src, version, options, obs), timeout) + // try + // let! result = computation + // return Some(result) + // with + // | :? System.TimeoutException -> + // LoggingService.logDebug "LanguageService: GetTypedParseResultWithTimeout: No stale results - typechecking with timeout - timeout exception occurred" + // return None + // | None -> + // LoggingService.logDebug "LanguageService: GetTypedParseResultWithTimeout: No stale results - typechecking without timeout" + // let! result = x.ParseAndCheckFile(fileName, SourceText.ofString src, version, options, obs) + // return Some(result) + //| None -> return None } + + ///// Returns a TypeParsedResults if available, otherwise None + //member x.GetTypedParseResultIfAvailable(projectFilename, fileName:string, src, stale) = + // let options = x.GetCheckerOptions(fileName, projectFilename, src) + // LoggingService.logDebug "LanguageService: GetTypedParseResultIfAvailable: file=%s" (Path.GetFileName(fileName)) + // options |> Option.bind(fun opts -> x.TryGetStaleTypedParseResult(fileName, opts, src, stale)) + + //member x.GetSymbolAtLocationInFile(projectFilename, fileName, version, source, line:int, col, lineStr) = + // asyncMaybe { + // LoggingService.logDebug "LanguageService: GetUsesOfSymbolAtLocationInFile: file:%s, line:%i, col:%i" (Path.GetFileName(fileName)) line col + // let! _colu, identIsland = MonoDevelop.FSharp.Shared.Parsing.findIdents col lineStr MonoDevelop.FSharp.Shared.SymbolLookupKind.ByLongIdent |> async.Return + // let! results = x.GetTypedParseResultWithTimeout(projectFilename, fileName, version, source, AllowStaleResults.MatchingSource) + // let! symbolUse = results.GetSymbolAtLocation(line, col, lineStr) + // let lastIdent = Seq.last identIsland + // return (lastIdent, symbolUse) } + + ///// Get all the uses of the specified symbol in the current project and optionally all dependent projects + //member x.GetUsesOfSymbolInProject(projectFilename, file, source, symbol:FSharpSymbol, ?dependentProjects) = + //async { + // LoggingService.logDebug "LanguageService: GetUsesOfSymbolInProject: project:%s, currentFile:%s, symbol:%s" projectFilename file symbol.DisplayName + // let sourceProjectOptions = x.GetCheckerOptions(file, projectFilename, source) + + // let! dependentProjectsOptions = + // defaultArg dependentProjects [] + // |> Async.List.map optionsForDependentProject + + // let! allProjectResults = + // sourceProjectOptions :: dependentProjectsOptions + // |> List.choose id + // |> Async.List.map checker.ParseAndCheckProject + + // let! allSymbolUses = + // allProjectResults + // |> List.map (fun checkedProj -> checkedProj.GetUsesOfSymbol(symbol)) + // |> Async.Parallel + // |> Async.map Array.concat + + // return allSymbolUses + //} + + //member x.MatchingBraces(filename, projectFilename, source) = + //let options = x.GetCheckerOptions(filename, projectFilename, source) + //match options with + //| Some opts -> + // let parseOptions, _errors = x.GetParsingOptionsFromProjectOptions opts + // checker.MatchBraces(filename, SourceText.ofString source, parseOptions) + //| None -> async { return [||] } + + /// Get all symbols derived from the specified symbol in the current project and optionally all dependent projects + //member x.GetDerivedSymbolsInProject(projectFilename, file, source, symbolAtCaret:FSharpSymbol, ?dependentProjects) = + // LoggingService.logDebug "Finding derived symbols in %s : Symbol %s" projectFilename symbolAtCaret.DisplayName + // let predicate (symbolUse: FSharpSymbolUse) = + // try + // match symbolAtCaret with + // | :? FSharpMemberOrFunctionOrValue as caretmfv -> + // match symbolUse.Symbol with + // | :? FSharpMemberOrFunctionOrValue as mfv -> + // let isOverrideOrDefault = mfv.IsOverrideOrExplicitInterfaceImplementation + // let baseTypeMatch() = + // maybe { + // let! ent = mfv.DeclaringEntity + // let! bt = ent.BaseType + // let! carentEncEnt = caretmfv.DeclaringEntity + // return carentEncEnt.IsEffectivelySameAs bt.TypeDefinition } + + // let nameMatch = mfv.DisplayName = caretmfv.DisplayName + // let parameterMatch() = + // let both = (mfv.CurriedParameterGroups |> Seq.concat) |> Seq.zip (caretmfv.CurriedParameterGroups |> Seq.concat) + // let allMatch = both |> Seq.forall (fun (one, two) -> one.Type = two.Type) + // allMatch + // let allmatch = nameMatch && isOverrideOrDefault && baseTypeMatch().IsSome && parameterMatch() + // allmatch + // | _ -> false + // | :? FSharpEntity as ent -> + // match symbolUse.Symbol with + // | :? FSharpEntity as fse -> + // match fse.BaseType with + // | Some basetype -> + // basetype.TypeDefinition.IsEffectivelySameAs ent + // | _ -> false + // | _ -> false + // | _ -> false + // with ex -> + // false + + // async { + // LoggingService.logDebug "LanguageService: GetDerivedSymbolInProject: proj:%s, file:%s, symbol:%s" projectFilename file symbolAtCaret.DisplayName + // let sourceProjectOptions = x.GetCheckerOptions(file, projectFilename, source) + + // let! dependentProjectsOptions = + // defaultArg dependentProjects [] + // |> Async.List.map optionsForDependentProject + + // let! allProjectResults = + // sourceProjectOptions :: dependentProjectsOptions + // |> List.choose id + // |> Async.List.map checker.ParseAndCheckProject + + // let! allSymbolUses = + // allProjectResults + // |> List.map (fun checkedProj -> checkedProj.GetAllUsesOfAllSymbols()) + // |> Async.Parallel + // |> Async.map Array.concat + + // let filteredSymbols = allSymbolUses |> Array.filter predicate + + // return filteredSymbols } + + ///// Get all overloads derived from the specified symbol in the current project + ////Currently there seems to be an issue in FCS where a methods EnclosingEntity returns the wrong type + ////The sanest option is to just use the OverloadsProperty for now. + //member x.GetOverridesForSymbol(symbolAtCaret:FSharpSymbol) = + // try + // match symbolAtCaret with + // | :? FSharpMemberOrFunctionOrValue as caretmfv -> + // caretmfv.Overloads(false) + // | _ -> None + // with _ -> None + + //member x.GetExtensionMethods(projectFilename, file, source, symbolAtCaret:FSharpSymbol, ?dependentProjects) = + + // let isAnAttributedExtensionMethod (symbolToCompare:FSharpMemberOrFunctionOrValue) parentEntity = + // let hasExtension = symbolToCompare.Attributes |> Seq.tryFind (fun a -> a.AttributeType.DisplayName = "ExtensionAttribute") |> Option.isSome + // if hasExtension then + // let firstCurriedParamter = symbolToCompare.CurriedParameterGroups.[0].[0] + // let sameAs = firstCurriedParamter.Type.TypeDefinition.IsEffectivelySameAs parentEntity + // sameAs + // else false + + // let isAnExtensionMethod (mfv:FSharpMemberOrFunctionOrValue) (parentEntity:FSharpSymbol) = + // let isExt = mfv.IsExtensionMember + // let extslogicalEntity = mfv.ApparentEnclosingEntity + // let sameLogicalParent = parentEntity.IsEffectivelySameAs extslogicalEntity + // isExt && sameLogicalParent + + // let predicate (symbolUse: FSharpSymbolUse) = + // try + // match symbolAtCaret with + // | :? FSharpEntity as caretEntity -> + // match symbolUse.Symbol with + // | :? FSharpMemberOrFunctionOrValue as mfv -> + // isAnExtensionMethod mfv caretEntity || isAnAttributedExtensionMethod mfv caretEntity + // | _ -> false + // | _ -> false + // with ex -> + // false + + // async { + // LoggingService.logDebug "LanguageService: GetExtensionMethods: proj:%s, file:%s, symbol:%s" projectFilename file symbolAtCaret.DisplayName + // let sourceProjectOptions = x.GetCheckerOptions(file, projectFilename, source) + // let dependentProjectsOptions = defaultArg dependentProjects [] |> List.map x.GetProjectCheckerOptions + + // let! allProjectResults = + // sourceProjectOptions :: dependentProjectsOptions + // |> List.choose id + // |> Async.List.map checker.ParseAndCheckProject + + // let! allSymbolUses = + // allProjectResults + // |> List.map (fun checkedProj -> checkedProj.GetAllUsesOfAllSymbols()) + // |> Async.Parallel + // |> Async.map Array.concat + + // let filteredSymbols = allSymbolUses |> Array.filter predicate + // return filteredSymbols } + + //member x.ParseAndCheckProject options = + // checker.ParseAndCheckProject(options) + + //member x.GetCachedProjectCheckResult (project:Project) = + // //TODO clear cache on project invalidation + // //should we? Or just wait for the checker to finish which will update it anyway. + // match checkProjectResultsCache.TryGetValue (project.FileName.ToString()) with + // | true, v -> Some v + // | false, _ -> None + + ///// This function is called when the project is know to have changed for reasons not encoded in the ProjectOptions + ///// e.g. dependent references have changed + //member x.InvalidateConfiguration(options) = + // LoggingService.logDebug "LanguageService: Invalidating configuration for:%s" (Path.GetFileName(options.ProjectFileName)) + // checker.InvalidateConfiguration(options) + + ////flush all caches and garbage collect + //member x.ClearRootCaches() = + //LoggingService.logDebug "LanguageService: Clearing root caches and finalizing transients" + //checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() + //checkProjectResultsCache.Clear() + //x.ClearProjectInfoCache() diff --git a/vsintegration/src/FSharp.Editor/Common/MDLanguageService.fs b/vsintegration/src/FSharp.Editor/Common/MDLanguageService.fs new file mode 100644 index 00000000000..b710d394865 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Common/MDLanguageService.fs @@ -0,0 +1,173 @@ +// -------------------------------------------------------------------------------------- +// Main file - contains types that call F# compiler service in the background, display +// error messages and expose various methods for to be used from MonoDevelop integration +// -------------------------------------------------------------------------------------- + +namespace MonoDevelop.FSharp +#nowarn "40" + +open System +open System.Collections.Generic +open System.Collections.Immutable +open System.Collections.ObjectModel +open System.IO +open System.Xml +open System.Text +open System.Diagnostics +//open ExtCore.Control +//open Mono.TextEditor +open MonoDevelop.Ide +open MonoDevelop.Ide.Editor +open MonoDevelop.Core +open MonoDevelop.Projects +open FSharp.Compiler.SourceCodeServices +open FSharp.Compiler.AbstractIL.Internal.Library +open MonoDevelop.Ide.TypeSystem + +module MonoDevelop = + + type TextEditor with + member x.GetLineInfoFromOffset (offset) = + let loc = x.OffsetToLocation(offset) + let line, col = max loc.Line 1, loc.Column - 1 + let currentLine = x.GetLineByOffset(offset) + let lineStr = x.Text.Substring(currentLine.Offset, currentLine.EndOffset - currentLine.Offset) + line, col, lineStr + + member x.GetLineInfoByCaretOffset () = + x.GetLineInfoFromOffset x.CaretOffset + + let inline private (>>=) a b = Option.bind b a + let inline private (!) a = Option.ofNull a + + type TypeSystem.ParsedDocument with + member x.TryGetAst() = + match x.Ast with + | null -> None + | :? ParseAndCheckResults as ast + -> Some ast + | _ -> None + + type DocumentContext with + member x.TryGetParsedDocument() = + !x >>=(fun pd -> !pd.ParsedDocument) + + member x.TryGetAst() = + x.TryGetParsedDocument() >>= (fun pd -> pd.TryGetAst()) + + member x.TryGetCheckResults() = + x.TryGetAst() >>= (fun ast -> ast.CheckResults) + + let internal getConfig () = + match IdeApp.Workspace with + | null -> ConfigurationSelector.Default + | ws -> + match ws.ActiveConfiguration with + | null -> ConfigurationSelector.Default + | config -> config + + + let visibleDocuments() = + IdeApp.Workbench.Documents + |> Seq.filter (fun doc -> match doc.Window with + | :? Gtk.Widget as w -> w.HasScreen + | _ -> false ) + + let isDocumentVisible filename = + visibleDocuments() + |> Seq.exists (fun d -> d.FileName = filename) + + let tryGetVisibleDocument filename = + visibleDocuments() + |> Seq.tryFind (fun d -> d.FileName = filename) + + +/// Provides functionality for working with the F# interactive checker running in background +type MDLanguageService() = + /// Single instance of the language service. We don't want the VFS during tests, so set it to blank from tests + /// before Instance is evaluated + static let mutable vfs = + lazy (let originalFs = Shim.FileSystem + let fs = new FileSystem(originalFs, (fun () -> seq { yield! match IdeApp.Workbench with + | null -> Seq.empty.ToImmutableList() + | _ -> IdeApp.Workbench.Documents })) + Shim.FileSystem <- fs + fs :> IFileSystem) + + static let mutable instance = + lazy + let _ = vfs.Force() + // VisualFSharp sets extraProjectInfo to be the Roslyn Workspace + // object, but we don't have that level of integration yet + let extraProjectInfo = None + new LanguageService( + (fun (changedfile, _) -> + try + let doc = IdeApp.Workbench.ActiveDocument + if doc <> null && doc.FileName.FullPath.ToString() = changedfile then + LoggingService.logDebug "FSharp Language Service: Compiler notifying document '%s' is dirty and needs reparsing. Reparsing as its the active document." (Path.GetFileName changedfile) + with exn -> + LoggingService.logDebug "FSharp Language Service: Error while attempting to notify document '%s' needs reparsing\n%s" (Path.GetFileName changedfile) (exn.ToString()) ), extraProjectInfo) + + static member Instance with get () = instance.Force () + and set v = instance <- lazy v + // Call this before Instance is called + static member DisableVirtualFileSystem() = + vfs <- lazy (Shim.FileSystem) + + static member invalidateProjectFile(projectFile: FilePath) = + try + if File.Exists (projectFile.FullPath.ToString()) then + MDLanguageService.Instance.TryGetProjectCheckerOptionsFromCache(projectFile.FullPath.ToString(), [("Configuration", IdeApp.Workspace.ActiveConfigurationId)]) + |> Option.iter(fun options -> + MDLanguageService.Instance.InvalidateConfiguration(options) + MDLanguageService.Instance.ClearProjectInfoCache()) + with ex -> LoggingService.LogError ("Could not invalidate configuration", ex) + + static member invalidateFiles (args:#ProjectFileEventInfo seq) = + for projectFileEvent in args do + if FileService.supportedFilePath projectFileEvent.ProjectFile.FilePath then + MDLanguageService.invalidateProjectFile(projectFileEvent.ProjectFile.FilePath) +[] +module MDLanguageServiceImpl = + let languageService = MDLanguageService.Instance + +/// Various utilities for working with F# language service +module internal ServiceUtils = + /// Translates icon code that we get from F# language service into a MonoDevelop icon + let getIcon (navItem: FSharpNavigationDeclarationItem) = + match navItem.Kind with + | NamespaceDecl -> "md-name-space" + | _ -> + match navItem.Glyph with + | FSharpGlyph.Class -> "md-class" + | FSharpGlyph.Enum -> "md-enum" + | FSharpGlyph.Struct -> "md-struct" + | FSharpGlyph.ExtensionMethod -> "md-struct" + | FSharpGlyph.Delegate -> "md-delegate" + | FSharpGlyph.Interface -> "md-interface" + | FSharpGlyph.Module -> "md-module" + | FSharpGlyph.NameSpace -> "md-name-space" + | FSharpGlyph.Method -> "md-method"; + | FSharpGlyph.OverridenMethod -> "md-method"; + | FSharpGlyph.Property -> "md-property" + | FSharpGlyph.Event -> "md-event" + | FSharpGlyph.Constant -> "md-field" + | FSharpGlyph.EnumMember -> "md-field" + | FSharpGlyph.Exception -> "md-exception" + | FSharpGlyph.Typedef -> "md-class" + | FSharpGlyph.Type -> "md-type" + | FSharpGlyph.Union -> "md-type" + | FSharpGlyph.Variable -> "md-field" + | FSharpGlyph.Field -> "md-field" + | FSharpGlyph.Error -> "md-breakpint" + +module internal KeywordList = + let modifiers = + dict [ + "abstract", """Indicates a method that either has no implementation in the type in which it is declared or that is virtual and has a default implementation.""" + "inline", """Used to indicate a function that should be integrated directly into the caller's code.""" + "mutable", """Used to declare a variable, that is, a value that can be changed.""" + "private", """Restricts access to a member to code in the same type or module.""" + "public", """Allows access to a member from outside the type.""" + ] diff --git a/vsintegration/src/FSharp.Editor/Common/OrderAssemblyReferences.fs b/vsintegration/src/FSharp.Editor/Common/OrderAssemblyReferences.fs new file mode 100644 index 00000000000..c8001a124c6 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Common/OrderAssemblyReferences.fs @@ -0,0 +1,113 @@ +namespace MonoDevelop.FSharp + +open System +open Mono.Cecil + +module Object = + let eqHack (f: 'a -> 'b) (x: 'a) (yobj: Object) : Boolean = + match yobj with + | :? 'a as y -> f x = f y + | _ -> false + + let compHack (f: 'a -> 'b) (x: 'a) (yobj: Object) : Int32 = + match yobj with + | :? 'a as y -> compare (f x) (f y) + | _ -> invalidArg "yobj" "Cannot compare elements of incompatible types" + +type Digraph<'n> when 'n : comparison = + Map<'n, Set<'n>> + +module Digraph = + + let addNode (n: 'n) (g: Digraph<'n>) : Digraph<'n> = + match Map.tryFind n g with + | None -> Map.add n Set.empty g + | Some _ -> g + + let addEdge ((n1, n2): 'n * 'n) (g: Digraph<'n>) : Digraph<'n> = + let g' = + match Map.tryFind n2 g with + | None -> addNode n2 g + | Some _ -> g + match Map.tryFind n1 g with + | None -> Map.add n1 (Set.singleton n2) g' + | Some ns -> Map.add n1 (Set.add n2 ns) g' + + let nodes (g: Digraph<'n>) : List<'n> = + Map.fold (fun xs k _ -> k::xs) [] g + + let roots (g: Digraph<'n>) : List<'n> = + List.filter (fun n -> not (Map.exists (fun _ v -> Set.contains n v) g)) (nodes g) + + let topSort (h: Digraph<'n>) : List<'n> = + let rec dfs (g: Digraph<'n>, order: List<'n>, rts: List<'n>) : List<'n> = + if List.isEmpty rts then + order + else + let n = List.head rts + let order' = n::order + let g' = Map.remove n g + let rts' = roots g' + dfs (g', order', rts') + dfs (h, [], roots h) + +[] +[] +[] +type AssemblyRef = + { + Path: String + Assembly: AssemblyDefinition + Name: String + } + + member this.show = this.ToString () + + override this.Equals (obj: Object) : bool = + Object.eqHack (fun (a:AssemblyRef) -> a.Name) this obj + + override this.GetHashCode () = + hash this.Name + + interface System.IComparable with + member this.CompareTo (obj: Object) = + Object.compHack (fun (p:AssemblyRef) -> p.Name) this obj + + override x.ToString () = x.Path + +[] +type OrderAssemblyReferences () = + + let mkGraph (seeds: seq) : Digraph = + + let findRef (s: seq) (m: AssemblyNameReference) = + match Seq.tryFind (fun r -> r.Name = m.FullName) seeds with + | None -> s + | Some ar -> Seq.append (Seq.singleton ar) s + + let processNode (g: Digraph) (n: AssemblyRef) = + let depNames = n.Assembly.MainModule.AssemblyReferences.ToArray() + let depRefs = Array.fold findRef Seq.empty depNames + Seq.fold (fun h c -> Digraph.addEdge (n, c) h) g depRefs + + let rec fixpoint (g: Digraph) = + let ns = Digraph.nodes g + let g' = List.fold processNode g ns + if g = g' then g else fixpoint g' + + fixpoint (Seq.fold (fun g s -> Digraph.addNode s g) Map.empty seeds) + + let mkAssemblyRef (t: String) = + let assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(t) + { + Path = t + Assembly = assemblyDefinition + Name = assemblyDefinition.FullName + } + + ///Orders the passed in array of assembly references in dependency order + member x.Order(rs: String[]) = + let asmRefs = Array.map mkAssemblyRef rs + let graph = mkGraph asmRefs + let ordering = Digraph.topSort graph + ordering diff --git a/vsintegration/src/FSharp.Editor/Common/Parameters.fs b/vsintegration/src/FSharp.Editor/Common/Parameters.fs new file mode 100644 index 00000000000..d15056530c0 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Common/Parameters.fs @@ -0,0 +1,88 @@ +// -------------------------------------------------------------------------------------- +// Serializable types that store F# project parameters (build order) and +// F# compiler parameters (debug mode, tail-calls, etc.) +// -------------------------------------------------------------------------------------- + +namespace MonoDevelop.FSharp + +open System +open MonoDevelop.Core.Serialization +open MonoDevelop.Projects + +/// Serializable type respresnting F# compiler parameters +type FSharpCompilerParameters() = + inherit MonoDevelop.Projects.DotNetCompilerParameters() + + [] + let mutable optimize = true + + [] + let mutable generateTailCalls = false + + [] + let mutable noStdLib = false + + [] + let mutable defineConstants = "" + + [] + let mutable otherFlags = "" + + [] + let mutable documentationFile = "" + + [] + let mutable platformTarget = "anycpu" + + [] + let mutable warnAsError = false + + [] + let mutable warningLevel = 4 + + [] + let mutable nowarn = String.Empty + + [] + let mutable debugType = "portable" + + member x.Optimize with get () = optimize and set v = optimize <- v + member x.GenerateTailCalls with get () = generateTailCalls and set v = generateTailCalls <- v + override x.NoStdLib with get () = noStdLib and set v = noStdLib <- v + member x.DefineConstants with get () = defineConstants and set v = defineConstants <- v + member x.OtherFlags with get () = otherFlags and set v = otherFlags <- v + member x.DocumentationFile with get () = documentationFile and set v = documentationFile <- v + member x.PlatformTarget with get () = platformTarget and set v = platformTarget <- v + member x.TreatWarningsAsErrors with get () = warnAsError and set v = warnAsError <- v + member x.WarningLevel with get () = warningLevel and set v = warningLevel <- v + member x.NoWarn with get () = nowarn and set v = nowarn <- v + member x.DebugType with get () = debugType and set v = debugType <- v + + override x.AddDefineSymbol(symbol) = + if System.String.IsNullOrEmpty x.DefineConstants then + x.DefineConstants <- symbol + else + x.DefineConstants <- x.DefineConstants + ";" + symbol + + override x.RemoveDefineSymbol(symbol) = + if x.DefineConstants = symbol then + x.DefineConstants <- "" + elif (String.IsNullOrWhiteSpace >> not) x.DefineConstants then + x.DefineConstants <- x.DefineConstants.Replace(";" + symbol, "") + + override x.GetDefineSymbols () = + if String.IsNullOrWhiteSpace x.DefineConstants then + Seq.empty + else + x.DefineConstants.Split (';', ',', ' ', '\t') + |> Seq.where (String.IsNullOrWhiteSpace >> not) + + override x.CreateCompilationOptions () = + null //TODO + + override x.CreateParseOptions (_) = + null //TODO + + override x.Write pset = + pset.SetPropertyOrder ("DebugSymbols", "DebugType", "Optimize", "OutputPath", "DefineConstants", "ErrorReport", "WarningLevel", "TreatWarningsAsErrors", "DocumentationFile"); + base.Write pset diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 3062ee177cd..8b2bd702384 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -2,12 +2,11 @@ - - - + Debug AnyCPU @@ -20,13 +19,11 @@ $(MDFrameworkVersion) win - --warnon:1182 Program true $(MSBuildProjectDirectory)\..\..\..\build\bin\MonoDevelop.exe $(MSBuildProjectDirectory)\..\..\..\build\bin - portable false ..\..\..\..\..\build\AddIns\FSharp.Editor @@ -58,18 +55,9 @@ - - False - $(RootDirectory)\build\bin\Xwt.dll - - - False - $(RootDirectory)\build\bin\Xwt.Gtk.dll - - @@ -85,6 +73,15 @@ + + + + + + + + + @@ -182,8 +179,6 @@ - - true Microsoft.VisualStudio.FSharp.Editor.SR @@ -191,23 +186,17 @@ FSharp.Editor.Designer.fs - - {3F5B5BDA-69D5-441A-8142-AA25C998A997} - MonoDevelop.TextEditor - - - - + + + - - - + {7525BB88-6142-4A26-93B9-A30C6983390A} MonoDevelop.Core @@ -216,18 +205,12 @@ {27096E7F-C91C-4AC6-B289-6897A701DF21} MonoDevelop.Ide - - {4C10F8F9-3816-4647-BA6E-85F5DE39883A} - MonoDevelop.FSharp - {91DD5A2D-9FE3-4C3C-9253-876141874DAD} Mono.Addins - - {AF5FEAD5-B50E-4F07-A274-32F23D5C504D} - MonoDevelop.FSharp.Shared - + + @@ -241,4 +224,4 @@ - + \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index fad4e32ed48..f967a8cc800 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -142,7 +142,8 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) //match legacyProjectSites.TryGetValue project.Id with //| true, site -> Some site //| _ -> None - + let mdLanguageService = new MonoDevelop.FSharp.LanguageService((fun (changedfile, _) -> ()), None) + let rec tryComputeOptions (project: Project) = async { let projectId = project.Id @@ -174,8 +175,8 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) if canBail then return None else - MonoDevelop.FSharp.MDLanguageService.DisableVirtualFileSystem() - let projectOpts = MonoDevelop.FSharp.MDLanguageService.Instance.GetProjectCheckerOptions(project.FilePath, [], refs) + //MonoDevelop.FSharp.MDLanguageService.DisableVirtualFileSystem() + let projectOpts = mdLanguageService.GetProjectCheckerOptions(project.FilePath, [], refs) //let otherOptions = // project.ProjectReferences // |> Seq.map (fun x -> "-r:" + project.Solution.GetProject(x.ProjectId).OutputFilePath) From c1c2b556a1cbbbed3afaebf93c6bc7922b9f63e2 Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 18 Feb 2020 16:47:17 +0000 Subject: [PATCH 024/101] Move Project type to fsharp-editor --- vsintegration/src/FSharp.Editor/FSharp.addin.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index 7f2251879e3..427e45c0c0c 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -14,14 +14,15 @@ - + + \ No newline at end of file From 6fb35c423011bc337ec27cac4ae62d6b05501f42 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 19 Feb 2020 11:42:42 +0000 Subject: [PATCH 025/101] Move F# Mime Types to FSharp.Editor --- .../src/FSharp.Editor/FSharp.addin.xml | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index 427e45c0c0c..0202c90863c 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -24,5 +24,27 @@ - + + + + + + + + + + + + + + + + + + \ No newline at end of file From 9a5010c9018703720c987c7686f3d52a2829e481 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 19 Feb 2020 12:04:04 +0000 Subject: [PATCH 026/101] Include .fsi files in editor --- vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs b/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs index 416b2bbb590..db98898923b 100644 --- a/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs +++ b/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs @@ -164,7 +164,7 @@ module CompilerArguments = project.Files // Shared Asset files need to be referenced first |> Seq.sortByDescending (fun f -> sharedAssetFiles.Contains f.FilePath) - |> Seq.filter(fun f -> f.FilePath.Extension = ".fs") + |> Seq.filter(fun f -> f.FilePath.Extension = ".fs" || f.FilePath.Extension = ".fsi") |> Seq.map(fun f -> f.Name) |> Seq.distinct From 1b98a2f8a4405b9be560d5308bbbb2d595eadfad Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 19 Feb 2020 15:41:47 +0000 Subject: [PATCH 027/101] Bump FCS to 34.0.1 --- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 8b2bd702384..7c73b8bc877 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -188,7 +188,7 @@ - + From 6af9c861953ad4364a0f4fafcb3e5e8a4a26b601 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 19 Feb 2020 16:44:24 +0000 Subject: [PATCH 028/101] Remove junk references --- vsintegration/src/FSharp.Editor/Common/FSharpProject.fs | 1 + vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs b/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs index 390294dad5b..2a1aa9c3260 100644 --- a/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs +++ b/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs @@ -9,6 +9,7 @@ open MonoDevelop.Projects open MonoDevelop.Projects.MSBuild open System.Xml open MonoDevelop.Core.Assemblies + //open ExtCore.Control open Microsoft.VisualStudio.FSharp.Editor.Pervasive module Project = diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 7c73b8bc877..efe6f3bc711 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -176,7 +176,6 @@ - @@ -194,7 +193,6 @@ - @@ -210,7 +208,6 @@ Mono.Addins - From 27de0e491f98ab5153fadac84befa93181d329d5 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 20 Feb 2020 10:07:40 +0000 Subject: [PATCH 029/101] Intellisense fixes --- .../src/FSharp.Editor/Completion/CompletionService.fs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index 3fd67c24bee..fa15b9d8e30 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -417,8 +417,15 @@ type internal FSharpCompletionSource //Data.CompletionStartData.DoesNotParticipateInCompletion //Data.CompletionStartData.ParticipatesInCompletionIfAny - let document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); - if document = null then + let document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges() + let doesNotParticipate = + match trigger.Character with + | '\n' | '<' | '(' -> true + | _ when (int trigger.Character) = 0 -> true + | _ when document = null -> true + | _ -> false + + if doesNotParticipate then Data.CompletionStartData.DoesNotParticipateInCompletion else match document.TryGetText() with From ca05f4e41c9ef776b4459d6ba246aebad8ff8786 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 20 Feb 2020 12:47:44 +0000 Subject: [PATCH 030/101] Intellisense fixes --- .../src/FSharp.Editor/Completion/CompletionService.fs | 8 ++++---- .../src/FSharp.Editor/LanguageService/Symbols.fs | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index fa15b9d8e30..ffcc0879352 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -384,7 +384,7 @@ type internal FSharpCompletionSource member __.GetDescriptionAsync(session, item, token) = async { let document = session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() - let! sourceText = document.GetTextAsync() |> Async.AwaitTask + //let! sourceText = document.GetTextAsync() |> Async.AwaitTask let provider = FSharpCompletionProvider(document.Project.Solution.Workspace, checkerProvider, projectInfoManager, assemblyContentProvider) let! description = provider.GetDescriptionAsync2(session.TextView, item, token) |> Async.AwaitTask let elements = description.TaggedParts |> buildClassifiedTextElements @@ -420,10 +420,10 @@ type internal FSharpCompletionSource let document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges() let doesNotParticipate = match trigger.Character with - | '\n' | '<' | '(' -> true - | _ when (int trigger.Character) = 0 -> true | _ when document = null -> true - | _ -> false + | '.' -> false + | c when Char.IsLetterOrDigit c -> false + | _ -> true if doesNotParticipate then Data.CompletionStartData.DoesNotParticipateInCompletion diff --git a/vsintegration/src/FSharp.Editor/LanguageService/Symbols.fs b/vsintegration/src/FSharp.Editor/LanguageService/Symbols.fs index a3d9b784526..3632b661bf4 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/Symbols.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/Symbols.fs @@ -16,7 +16,6 @@ open FSharp.Compiler.Ast open FSharp.Compiler.SourceCodeServices open System.IO - [] type SymbolDeclarationLocation = | CurrentDocument From 4c8b49f8a5f2fd0713ba83cda7c3275af39ba736 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 20 Feb 2020 14:05:42 +0000 Subject: [PATCH 031/101] Intellisense fixes --- .../AsyncCompletionCommitManagerProvider.fs | 1 + .../Completion/CompletionProvider.fs | 26 +++++++-------- .../Completion/CompletionService.fs | 33 +++++++++++-------- .../src/FSharp.Editor/FSharp.Editor.fsproj | 2 +- .../InlineRename/InlineRenameService.fs | 1 - 5 files changed, 34 insertions(+), 29 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManagerProvider.fs b/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManagerProvider.fs index a4e70e2870c..f641bb1edbb 100644 --- a/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManagerProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManagerProvider.fs @@ -19,5 +19,6 @@ type FSharpAsyncCompletionCommitManagerProvider() = let x = 1 interface IAsyncCompletionCommitManagerProvider with member __.GetOrCreate(textView) = + System.Diagnostics.Trace.Write("Hello") System.Diagnostics.Trace.WriteLine("GetOrCreate FSharpAsyncCompletionCommitManager") FSharpAsyncCompletionCommitManager() :> _ \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index 16fc043af15..28ad4b3bad0 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -80,16 +80,16 @@ type internal FSharpCompletionProvider static let mruItems = Dictionary<(* Item.FullName *) string, (* hints *) int>() - static member ShouldTriggerCompletionAux(sourceText: SourceText, caretPosition: int, trigger: CompletionTriggerKind, getInfo: (unit -> DocumentId * string * string list), intelliSenseOptions: IntelliSenseOptions) = + static member ShouldTriggerCompletionAux(sourceText: SourceText, caretPosition: int, trigger: Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionTrigger, getInfo: (unit -> DocumentId * string * string list), intelliSenseOptions: IntelliSenseOptions) = if caretPosition = 0 then false else let triggerPosition = caretPosition - 1 - let triggerChar = sourceText.[triggerPosition] + let triggerChar = trigger.Character - if trigger = CompletionTriggerKind.Deletion && intelliSenseOptions.ShowAfterCharIsDeleted then - Char.IsLetterOrDigit(sourceText.[triggerPosition]) || triggerChar = '.' - elif not (trigger = CompletionTriggerKind.Insertion) then + if trigger.Reason = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionTriggerReason.Deletion && intelliSenseOptions.ShowAfterCharIsDeleted then + Char.IsLetterOrDigit(triggerChar) || triggerChar = '.' + elif not (trigger.Reason = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionTriggerReason.Insertion) then false else // Do not trigger completion if it's not single dot, i.e. range expression @@ -222,16 +222,16 @@ type internal FSharpCompletionProvider return results } - override this.ShouldTriggerCompletion(sourceText: SourceText, caretPosition: int, trigger: CompletionTrigger, _: OptionSet) = - use _logBlock = Logger.LogBlock LogEditorFunctionId.Completion_ShouldTrigger + //override this.ShouldTriggerCompletion(sourceText: SourceText, caretPosition: int, trigger: CompletionTrigger, _: OptionSet) = + // use _logBlock = Logger.LogBlock LogEditorFunctionId.Completion_ShouldTrigger - let getInfo() = - let documentId = workspace.GetDocumentIdInCurrentContext(sourceText.Container) - let document = workspace.CurrentSolution.GetDocument(documentId) - let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) - (documentId, document.FilePath, defines) + // let getInfo() = + // let documentId = workspace.GetDocumentIdInCurrentContext(sourceText.Container) + // let document = workspace.CurrentSolution.GetDocument(documentId) + // let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) + // (documentId, document.FilePath, defines) - FSharpCompletionProvider.ShouldTriggerCompletionAux(sourceText, caretPosition, trigger.Kind, getInfo, settings.IntelliSense) + // FSharpCompletionProvider.ShouldTriggerCompletionAux(sourceText, caretPosition, trigger, getInfo, settings.IntelliSense) override this.ProvideCompletionsAsync(context: Completion.CompletionContext) = asyncMaybe { diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index ffcc0879352..50c832f0bea 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -416,27 +416,32 @@ type internal FSharpCompletionSource System.Diagnostics.Trace.WriteLine("initialize") //Data.CompletionStartData.DoesNotParticipateInCompletion //Data.CompletionStartData.ParticipatesInCompletionIfAny + use _logBlock = Logger.LogBlock LogEditorFunctionId.Completion_ShouldTrigger let document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges() - let doesNotParticipate = - match trigger.Character with - | _ when document = null -> true - | '.' -> false - | c when Char.IsLetterOrDigit c -> false - | _ -> true - - if doesNotParticipate then - Data.CompletionStartData.DoesNotParticipateInCompletion - else - match document.TryGetText() with - | true, sourceText -> + + let getInfo() = + //let documentId = workspace.GetDocumentIdInCurrentContext(sourceText.Container) + //let document = workspace.CurrentSolution.GetDocument(documentId) + let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) + (document.Id, document.FilePath, defines) + + match document.TryGetText() with + | true, sourceText -> + let shouldTrigger = + FSharpCompletionProvider.ShouldTriggerCompletionAux(sourceText, triggerLocation.Position, trigger, getInfo, settings.IntelliSense) + + match shouldTrigger with + | false -> + Data.CompletionStartData.DoesNotParticipateInCompletion + | true -> Data.CompletionStartData( participation = Data.CompletionParticipation.ProvidesItems, applicableToSpan = new SnapshotSpan( triggerLocation.Snapshot, CompletionUtils.getCompletionItemSpan sourceText triggerLocation.Position)) - | false, _ -> - Data.CompletionStartData.DoesNotParticipateInCompletion + | false, _ -> + Data.CompletionStartData.DoesNotParticipateInCompletion [)>] diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index efe6f3bc711..287e4a22fdd 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -141,7 +141,6 @@ - @@ -208,6 +207,7 @@ Mono.Addins + diff --git a/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs b/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs index 8791c558896..4af0a4a39a3 100644 --- a/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs +++ b/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs @@ -159,7 +159,6 @@ type internal InlineRenameService let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, options, userOpName = userOpName) let! symbolUse = checkFileResults.GetSymbolUseAtLocation(fcsTextLineNumber, symbol.Ident.idRange.EndColumn, textLine.Text.ToString(), symbol.FullIsland, userOpName=userOpName) let! declLoc = symbolUse.GetDeclarationLocation(document) - let! span = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate) let triggerSpan = Tokenizer.fixupSpan(sourceText, span) From 2a23e4b2a0281d001646f4fd7d4081cf161b204f Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 21 Feb 2020 00:10:28 +0000 Subject: [PATCH 032/101] Bump FCS to 34.0.1 --- .../Diagnostics/DocumentDiagnosticAnalyzer.fs | 12 ++++++- .../src/FSharp.Editor/FSharp.Editor.fsproj | 36 +++++++++---------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs index d9fe8b811d2..37c61dff5b5 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs @@ -62,7 +62,17 @@ type internal FSharpDocumentDiagnosticAnalyzer [] () = static member GetDiagnostics(checker: FSharpChecker, filePath: string, sourceText: SourceText, textVersionHash: int, parsingOptions: FSharpParsingOptions, options: FSharpProjectOptions, diagnosticType: DiagnosticsType) = async { let fsSourceText = sourceText.ToFSharpSourceText() - let! parseResults = checker.ParseFile(filePath, fsSourceText, parsingOptions, userOpName=userOpName) + + let! parseResults = + try + checker.ParseFile(filePath, fsSourceText, parsingOptions, userOpName=userOpName) + with + | :? StackOverflowException as e -> + LoggingService.logError "%s" (e.ToString()) + LoggingService.logError "StackOverflow while parsing %s" filePath + failwithf "StackOverflow parsing %s" filePath + + let! errors = async { match diagnosticType with diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 287e4a22fdd..53bb17c6b86 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -141,6 +141,7 @@ + @@ -184,30 +185,29 @@ FSharp.Editor.Designer.fs - - - - - - - - - - - - {7525BB88-6142-4A26-93B9-A30C6983390A} - MonoDevelop.Core + + + {91DD5A2D-9FE3-4C3C-9253-876141874DAD} + Mono.Addins {27096E7F-C91C-4AC6-B289-6897A701DF21} MonoDevelop.Ide - - {91DD5A2D-9FE3-4C3C-9253-876141874DAD} - Mono.Addins + + {7525BB88-6142-4A26-93B9-A30C6983390A} + MonoDevelop.Core - - + + + + + + + + + + From 2aac7adcb64a595c0c593668e6fcdb62fc312430 Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 21 Feb 2020 00:51:54 +0000 Subject: [PATCH 033/101] Don't optimize in release mode --- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 53bb17c6b86..c2e11cc7b1c 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -25,7 +25,7 @@ $(MSBuildProjectDirectory)\..\..\..\build\bin\MonoDevelop.exe $(MSBuildProjectDirectory)\..\..\..\build\bin portable - false + true ..\..\..\..\..\build\AddIns\FSharp.Editor 3 ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML @@ -38,6 +38,12 @@ ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML + + false + ;RELEASE + ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML + true + From ca7fd462e15037e97ca0041d3d86a5a489e3dbff Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 21 Feb 2020 09:32:33 +0000 Subject: [PATCH 034/101] TailCalls --- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index c2e11cc7b1c..4ce4eb32dae 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -34,15 +34,13 @@ true --publicsign ..\..\..\src\buildtools\keys\MSFT.snk - - ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML false ;RELEASE - ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML true + true From b0fcb9f47a6ef26fe6bb405c880e6a21f2025241 Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 21 Feb 2020 10:07:08 +0000 Subject: [PATCH 035/101] Fix project loaded indicator --- .../src/FSharp.Editor/Common/LanguageService.fs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Common/LanguageService.fs b/vsintegration/src/FSharp.Editor/Common/LanguageService.fs index 10ad0372da8..8d6b7a375e8 100644 --- a/vsintegration/src/FSharp.Editor/Common/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/Common/LanguageService.fs @@ -245,14 +245,12 @@ type LanguageService(dirtyNotify, _extraProjectInfo) as x = let loadingProjects = HashSet() let showStatusIcon projectFileName = - () - //if loadingProjects.Add projectFileName then - //IdeApp.TypeSystemService.BeginWorkspaceLoad() + if loadingProjects.Add projectFileName then + IdeApp.TypeSystemService.BeginWorkspaceLoad() let hideStatusIcon projectFileName = - () - //if loadingProjects.Remove projectFileName then - //IdeApp.TypeSystemService.EndWorkspaceLoad() + if loadingProjects.Remove projectFileName then + IdeApp.TypeSystemService.EndWorkspaceLoad() // Create an instance of interactive checker. The callback is called by the F# compiler service // when its view of the prior-typechecking-state of the start of a file has changed, for example From 2aecebd5bb5e65f4c18777ed78eab8f2fd4316be Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 21 Feb 2020 13:49:45 +0000 Subject: [PATCH 036/101] Fix IVT and hide workspace status icon --- vsintegration/src/FSharp.Editor/Common/LanguageService.fs | 6 +++++- .../LanguageService/FSharpProjectOptionsManager.fs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Common/LanguageService.fs b/vsintegration/src/FSharp.Editor/Common/LanguageService.fs index 8d6b7a375e8..52ab586420e 100644 --- a/vsintegration/src/FSharp.Editor/Common/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/Common/LanguageService.fs @@ -196,7 +196,7 @@ type AllowStaleResults = open Microsoft.VisualStudio.FSharp.Editor.Pervasive /// Provides functionality for working with the F# interactive checker running in background -type LanguageService(dirtyNotify, _extraProjectInfo) as x = +type LanguageService(checker: FSharpChecker, dirtyNotify, _extraProjectInfo) as x = /// Load times used to reset type checking properly on script/project load/unload. It just has to be unique for each project load/reload. /// Not yet sure if this works for scripts. @@ -416,6 +416,10 @@ type LanguageService(dirtyNotify, _extraProjectInfo) as x = // Some entry //| _, cache -> showStatusIcon projFilename + + checker.ProjectChecked.Add (fun (filename, _) -> + hideStatusIcon filename) + let project = IdeApp.Workspace.GetAllProjects() |> Seq.tryFind (fun p -> p.FileName.FullPath.ToString() = projFilename) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index f967a8cc800..b3717582131 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -142,7 +142,7 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) //match legacyProjectSites.TryGetValue project.Id with //| true, site -> Some site //| _ -> None - let mdLanguageService = new MonoDevelop.FSharp.LanguageService((fun (changedfile, _) -> ()), None) + let mdLanguageService = new MonoDevelop.FSharp.LanguageService(checkerProvider.Checker, (fun (changedfile, _) -> ()), None) let rec tryComputeOptions (project: Project) = async { From cca764a079929adc200d594708044baa81d91476 Mon Sep 17 00:00:00 2001 From: nosami Date: Sat, 22 Feb 2020 13:01:57 +0000 Subject: [PATCH 037/101] Add support for .fsx files --- .../FSharp.Editor/Common/CompilerArguments.fs | 4 +-- .../FSharpProjectOptionsManager.fs | 25 +++++++++++++++---- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs b/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs index db98898923b..fa53675522c 100644 --- a/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs +++ b/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs @@ -192,8 +192,8 @@ module CompilerArguments = yield "--flaterrors" for symbol in defines do yield "--define:" + symbol yield if fsconfig.HasDefineSymbol "DEBUG" then "--debug+" else "--debug-" - yield if fsconfig.Optimize then "--optimize+" else "--optimize-" - yield if fsconfig.GenerateTailCalls then "--tailcalls+" else "--tailcalls-" + yield "--optimize-" + yield "--tailcalls+" if not (String.IsNullOrWhiteSpace fsconfig.DebugType) then yield sprintf "--debug:%s" fsconfig.DebugType yield match project.CompileTarget with diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index b3717582131..2794461b642 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -20,7 +20,7 @@ open System.Threading //open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.LanguageServices.Implementation.TaskList open Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices - +open MonoDevelop.FSharp //[] //module private FSharpProjectOptionsHelpers = @@ -100,7 +100,22 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) let! scriptProjectOptions, _ = checkerProvider.Checker.GetProjectOptionsFromScript(document.FilePath, sourceText.ToFSharpSourceText()) let projectOptions = if isScriptFile document.FilePath then - scriptProjectOptions + + if scriptProjectOptions.OtherOptions |> Seq.exists (fun s -> s.Contains("FSharp.Core.dll")) then scriptProjectOptions + else + // Add assemblies that may be missing in the standard assembly resolution + LoggingService.logDebug "LanguageService: GetScriptCheckerOptions: Adding missing core assemblies." + let dirs = FSharpEnvironment.getDefaultDirectories (None, FSharpTargetFramework.NET_4_5 ) + { scriptProjectOptions with + OtherOptions = + [| yield! scriptProjectOptions.OtherOptions + match FSharpEnvironment.resolveAssembly dirs "FSharp.Core" with + | Some fn -> yield String.Format ("-r:{0}", fn) + | None -> + LoggingService.logDebug "LanguageService: Resolution: FSharp.Core assembly resolution failed!" + match FSharpEnvironment.resolveAssembly dirs "FSharp.Compiler.Interactive.Settings" with + | Some fn -> yield String.Format ("-r:{0}", fn) + | None -> LoggingService.logDebug "LanguageService: Resolution: FSharp.Compiler.Interactive.Settings assembly resolution failed!" |]} else { ProjectFileName = document.FilePath @@ -116,7 +131,7 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) ExtraProjectInfo= None Stamp = Some(int64 (fileStamp.GetHashCode())) } - + checkerProvider.Checker.CheckProjectInBackground(projectOptions, userOpName="checkOptions") let parsingOptions, _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions) @@ -242,9 +257,9 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) reply.Reply None else //try - // For now, disallow miscellaneous workspace since we are using the hacky F# miscellaneous files project. if document.Project.Solution.Workspace.Kind = WorkspaceKind.MiscellaneousFiles then - reply.Reply None + let! options = tryComputeOptionsByFile document ct + reply.Reply options elif document.Project.Name = FSharpConstants.FSharpMiscellaneousFilesName then let! options = tryComputeOptionsByFile document ct reply.Reply options From b379cce2f6702196c0c590cee306750f78bd92f8 Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 25 Feb 2020 13:20:37 +0000 Subject: [PATCH 038/101] Bump FCS --- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 4ce4eb32dae..21d3f30e089 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -208,7 +208,7 @@ - + From f5c04dc12a9e8fdcaa22452d7ea04a39b6ef6e43 Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 25 Feb 2020 13:21:20 +0000 Subject: [PATCH 039/101] Fix resx translations --- .../CodeFix/AddNewKeywordToDisposableConstructorInvocation.fs | 2 +- vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs | 1 + vsintegration/src/FSharp.Editor/CodeFix/SimplifyName.fs | 4 ++-- vsintegration/src/FSharp.Editor/Common/FSharpProject.fs | 1 - .../src/FSharp.Editor/DocComments/XMLDocumentation.fs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddNewKeywordToDisposableConstructorInvocation.fs b/vsintegration/src/FSharp.Editor/CodeFix/AddNewKeywordToDisposableConstructorInvocation.fs index ed979c0d216..0253a220ae7 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/AddNewKeywordToDisposableConstructorInvocation.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/AddNewKeywordToDisposableConstructorInvocation.fs @@ -19,7 +19,7 @@ type internal FSharpAddNewKeywordCodeFixProvider() = override this.RegisterCodeFixesAsync context : Task = async { - let title = "SR.AddNewKeyword()" + let title = SR.AddNewKeyword() context.RegisterCodeFix( CodeAction.Create( title, diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs index 8b659aafb32..c89282eea3a 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs @@ -5,6 +5,7 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System.Composition open System.Threading open System.Threading.Tasks +open System.Threading.Tasks open Microsoft.CodeAnalysis.Diagnostics open Microsoft.CodeAnalysis.Text diff --git a/vsintegration/src/FSharp.Editor/CodeFix/SimplifyName.fs b/vsintegration/src/FSharp.Editor/CodeFix/SimplifyName.fs index 3c9320a5805..a2768640387 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/SimplifyName.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/SimplifyName.fs @@ -25,8 +25,8 @@ type internal FSharpSimplifyNameCodeFixProvider() = for diagnostic in context.Diagnostics |> Seq.filter (fun x -> x.Id = fixableDiagnosticId) do let title = match diagnostic.Properties.TryGetValue(SimplifyNameDiagnosticAnalyzer.LongIdentPropertyKey) with - | true, longIdent -> sprintf "%s '%s'" ("SR.SimplifyName()") longIdent - | _ -> "SR.SimplifyName()" + | true, longIdent -> sprintf "%s '%s'" (SR.SimplifyName()) longIdent + | _ -> SR.SimplifyName() let codefix = CodeFixHelpers.createTextChangeCodeFix(title, context, (fun () -> asyncMaybe.Return [| TextChange(context.Span, "") |])) diff --git a/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs b/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs index 2a1aa9c3260..7085af97970 100644 --- a/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs +++ b/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs @@ -7,7 +7,6 @@ open MonoDevelop.Core open MonoDevelop.Core.Serialization open MonoDevelop.Projects open MonoDevelop.Projects.MSBuild -open System.Xml open MonoDevelop.Core.Assemblies //open ExtCore.Control diff --git a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs index c365cf8066c..be060a80030 100644 --- a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs +++ b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs @@ -425,7 +425,7 @@ module internal XmlDocumentation = let ProcessGenericParameters (tps: Layout list) = if not tps.IsEmpty then AppendHardLine typeParameterMapCollector - AppendOnNewLine typeParameterMapCollector ("SR.GenericParametersHeader()") + AppendOnNewLine typeParameterMapCollector (SR.GenericParametersHeader()) for tp in tps do AppendHardLine typeParameterMapCollector typeParameterMapCollector.Add(tagSpace " ") From 9d430465ffd8b33bcfbbc589553f724e4addd36c Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 25 Feb 2020 14:54:27 +0000 Subject: [PATCH 040/101] Bump FCS --- .../FSharp.Editor/Classification/ClassificationService.fs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs index acc13b6155a..c57451e46fd 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs @@ -86,9 +86,9 @@ type internal FSharpClassificationService let! _, _, checkResults = checkerProvider.Checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, allowStaleResults = false, userOpName=userOpName) // it's crucial to not return duplicated or overlapping `ClassifiedSpan`s because Find Usages service crashes. let targetRange = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, textSpan, sourceText) - let classificationData = checkResults.GetSemanticClassification (Some targetRange) |> Array.distinctBy fst + let classificationData = checkResults.GetSemanticClassification (Some targetRange) - for (range, classificationType) in classificationData do + for struct (range, classificationType) in classificationData do match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range) with | None -> () | Some span -> @@ -97,7 +97,6 @@ type internal FSharpClassificationService | SemanticClassificationType.Printf -> span | _ -> Tokenizer.fixupSpan(sourceText, span) result.Add(ClassifiedSpan(span, FSharpClassificationTypes.getClassificationTypeName(classificationType))) - //result.Add(ClassifiedSpan(span, classificationType.ToString())) } |> Async.Ignore |> RoslynHelpers.StartAsyncUnitAsTask cancellationToken From 2e44cfc4ee3ac6be01883a3b7275ced2cb1e009e Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 27 Feb 2020 14:05:48 +0000 Subject: [PATCH 041/101] Switch logging to MD LoggingService --- .../src/FSharp.Editor/Common/Logging.fs | 75 +++---------------- 1 file changed, 9 insertions(+), 66 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Common/Logging.fs b/vsintegration/src/FSharp.Editor/Common/Logging.fs index 59f24b42b98..2c20eb965d6 100644 --- a/vsintegration/src/FSharp.Editor/Common/Logging.fs +++ b/vsintegration/src/FSharp.Editor/Common/Logging.fs @@ -6,6 +6,8 @@ open System.ComponentModel.Composition open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.FSharp.Editor +open MonoDevelop.Core + [] type LogType = | Info @@ -19,76 +21,17 @@ type LogType = | Warn -> "Warning" | Error -> "Error" - -module Config = - let [] fsharpOutputGuidString = "E721F849-446C-458C-997A-99E14A04CFD3" - let fsharpOutputGuid = Guid fsharpOutputGuidString - -open Config - -type [] Logger [] - //([)>] serviceProvider: IServiceProvider) = - () = - //let outputWindow = serviceProvider.GetService() |> Option.ofObj - - let createPane () = () - //outputWindow |> Option.iter (fun x -> - //x.CreatePane(ref fsharpOutputGuid,"F# Language Service", Convert.ToInt32 true, Convert.ToInt32 false) |> ignore) - - do createPane () - - let getPane () = - //match outputWindow |> Option.map (fun x -> x.GetPane (ref fsharpOutputGuid)) with - //| Some (0, pane) -> - // pane.Activate() |> ignore - // Some pane - //| _ -> None - None - - //static let mutable globalServiceProvider: IServiceProvider option = None - - //static member GlobalServiceProvider - //with get () = globalServiceProvider |> Option.defaultValue (ServiceProvider.GlobalProvider :> IServiceProvider) - //and set v = globalServiceProvider <- Some v - - member __.FSharpLoggingPane - with get () = - getPane () - |> function - | Some pane -> Some pane - | None -> - createPane() - getPane() - - member self.Log (msgType:LogType,msg:string) = - let time = DateTime.Now.ToString("hh:mm:ss tt") - match self.FSharpLoggingPane, msgType with - | None, _ -> MonoDevelop.Core.LoggingService.LogDebug msg - //| Some pane, LogType.Message -> String.Format("[F#][{0}{1}] {2}{3}", "" , time, msg, Environment.NewLine) |> pane.OutputString |> ignore - //| Some pane, LogType.Info -> String.Format("[F#][{0}{1}] {2}{3}", "INFO " , time, msg, Environment.NewLine) |> pane.OutputString |> ignore - //| Some pane, LogType.Warn -> String.Format("[F#][{0}{1}] {2}{3}", "WARN " , time, msg, Environment.NewLine) |> pane.OutputString |> ignore - //| Some pane, LogType.Error -> String.Format("[F#][{0}{1}] {2}{3}", "ERROR ", time, msg, Environment.NewLine) |> pane.OutputString |> ignore - | Some _pane, LogType.Message -> String.Format("[F#][{0}{1}] {2}{3}", "" , time, msg, Environment.NewLine) |> printf "%s" - | Some _pane, LogType.Info -> String.Format("[F#][{0}{1}] {2}{3}", "INFO " , time, msg, Environment.NewLine) |> printf "%s" - | Some _pane, LogType.Warn -> String.Format("[F#][{0}{1}] {2}{3}", "WARN " , time, msg, Environment.NewLine) |> printf "%s" - | Some _pane, LogType.Error -> String.Format("[F#][{0}{1}] {2}{3}", "ERROR ", time, msg, Environment.NewLine) |> printf "%s" [] module Logging = + let inline private log f = Printf.kprintf f - let inline debug msg = Printf.kprintf Debug.WriteLine msg - - let private logger = lazy Logger((*Logger.GlobalServiceProvider*)) - let private log logType msg = logger.Value.Log(logType,msg) - - let logMsg msg = log LogType.Message msg - let logInfo msg = log LogType.Info msg - let logWarning msg = log LogType.Warn msg - let logError msg = log LogType.Error msg + let inline private logWithThread f format = + log (log f "[UI - %b] %s" Runtime.IsMainThread) format - let logMsgf msg = Printf.kprintf (log LogType.Message) msg - let logInfof msg = Printf.kprintf (log LogType.Info) msg - let logWarningf msg = Printf.kprintf (log LogType.Warn) msg - let logErrorf msg = Printf.kprintf (log LogType.Error) msg + let logDebug format = logWithThread LoggingService.LogDebug format + let logErrorf format = logWithThread LoggingService.LogError format + let logInfof format = logWithThread LoggingService.LogInfo format + let logWarning format = logWithThread LoggingService.LogWarning format let logException (ex: Exception) = logErrorf "Exception Message: %s\nStack Trace: %s" ex.Message ex.StackTrace From 4e7fe8026a1d61042804cc8950350c01f55f67a3 Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 28 Feb 2020 07:43:00 +0000 Subject: [PATCH 042/101] Add workspace invalidation --- .../FSharpProjectOptionsManager.fs | 73 ++++++++++--------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index 2794461b642..ec54745a420 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -21,8 +21,11 @@ open System.Threading open Microsoft.VisualStudio.LanguageServices.Implementation.TaskList open Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices open MonoDevelop.FSharp -//[] -//module private FSharpProjectOptionsHelpers = +open MonoDevelop.Ide +open MonoDevelop.Ide.TypeSystem + +[] +module private FSharpProjectOptionsHelpers = //let mapCpsProjectToSite(project:Project, cpsCommandLineOptions: IDictionary) = // let sourcePaths, referencePaths, options = @@ -50,27 +53,27 @@ open MonoDevelop.FSharp // //member __.BuildErrorReporter with get () = errorReporter and set (v) = errorReporter <- v // } - //let hasProjectVersionChanged (oldProject: Project) (newProject: Project) = - // oldProject.Version <> newProject.Version - - //let hasDependentVersionChanged (oldProject: Project) (newProject: Project) = - // let oldProjectRefs = oldProject.ProjectReferences - // let newProjectRefs = newProject.ProjectReferences - // oldProjectRefs.Count() <> newProjectRefs.Count() || - // (oldProjectRefs, newProjectRefs) - // ||> Seq.exists2 (fun p1 p2 -> - // let doesProjectIdDiffer = p1.ProjectId <> p2.ProjectId - // let p1 = oldProject.Solution.GetProject(p1.ProjectId) - // let p2 = newProject.Solution.GetProject(p2.ProjectId) - // doesProjectIdDiffer || p1.Version <> p2.Version - // ) - - //let isProjectInvalidated (oldProject: Project) (newProject: Project) (settings: EditorOptions) = - //let hasProjectVersionChanged = hasProjectVersionChanged oldProject newProject - //if settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences then - // hasProjectVersionChanged || hasDependentVersionChanged oldProject newProject - //else - //hasProjectVersionChanged + let hasProjectVersionChanged (oldProject: Project) (newProject: Project) = + oldProject.Version <> newProject.Version + + let hasDependentVersionChanged (oldProject: Project) (newProject: Project) = + let oldProjectRefs = oldProject.ProjectReferences + let newProjectRefs = newProject.ProjectReferences + oldProjectRefs.Count() <> newProjectRefs.Count() || + (oldProjectRefs, newProjectRefs) + ||> Seq.exists2 (fun p1 p2 -> + let doesProjectIdDiffer = p1.ProjectId <> p2.ProjectId + let p1 = oldProject.Solution.GetProject(p1.ProjectId) + let p2 = newProject.Solution.GetProject(p2.ProjectId) + doesProjectIdDiffer || p1.Version <> p2.Version + ) + + let isProjectInvalidated (oldProject: Project) (newProject: Project) (settings: EditorOptions) = + let hasProjectVersionChanged = hasProjectVersionChanged oldProject newProject + if settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences then + hasProjectVersionChanged || hasDependentVersionChanged oldProject newProject + else + hasProjectVersionChanged [] type private FSharpProjectOptionsMessage = @@ -241,10 +244,10 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) return Some(parsingOptions, projectOptions) | true, (oldProject, parsingOptions, projectOptions) -> - //if isProjectInvalidated oldProject project settings then - // cache.Remove(projectId) |> ignore - // return! tryComputeOptions project - //else + if isProjectInvalidated oldProject project settings then + cache.Remove(projectId) |> ignore + return! tryComputeOptions project + else return Some(parsingOptions, projectOptions) } @@ -343,13 +346,15 @@ type internal FSharpProjectOptionsManager let reactor = new FSharpProjectOptionsReactor(settings, (*serviceProvider,*) checkerProvider) - //do - //// We need to listen to this event for lifecycle purposes. - //workspace.WorkspaceChanged.Add(fun args -> - // match args.Kind with - // | WorkspaceChangeKind.ProjectRemoved -> reactor.ClearOptionsByProjectId(args.ProjectId) - // | _ -> () - //) + do + let workspace = IdeApp.TypeSystemService.Workspace + + // We need to listen to this event for lifecycle purposes. + workspace.WorkspaceChanged.Add(fun args -> + match args.Kind with + | WorkspaceChangeKind.ProjectRemoved -> reactor.ClearOptionsByProjectId(args.ProjectId) + | _ -> () + ) member __.SetLegacyProjectSite (projectId, projectSite) = reactor.SetLegacyProjectSite (projectId, projectSite) From 7902505b2b3c0d7ee676239f98a085acef6a7c99 Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 3 Mar 2020 17:19:41 +0000 Subject: [PATCH 043/101] Add Navigation bar support --- .../src/FSharp.Editor/FSharp.Editor.fsproj | 45 ++- .../VSMac/FSharpPathedDocumentExtension.fs | 276 ++++++++++++++++++ .../FSharpPathedDocumentExtensionProvider.fs | 50 ++++ 3 files changed, 359 insertions(+), 12 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtension.fs create mode 100644 vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtensionProvider.fs diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 21d3f30e089..df1b2e80eb1 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -1,12 +1,7 @@  - - - - + Debug AnyCPU @@ -15,9 +10,7 @@ FSharp.Editor False False - $(MDFrameworkVersion) - win --warnon:1182 Program @@ -41,14 +34,23 @@ ;RELEASE true true + false + false + false + false + false + + + false + false + false + false + false - - - @@ -58,10 +60,10 @@ - + @@ -188,19 +190,26 @@ PublicResXFileCodeGenerator FSharp.Editor.Designer.fs + + ..\..\..\..\Xamarin.Mac.dll + False + {91DD5A2D-9FE3-4C3C-9253-876141874DAD} Mono.Addins + {27096E7F-C91C-4AC6-B289-6897A701DF21} MonoDevelop.Ide + {7525BB88-6142-4A26-93B9-A30C6983390A} MonoDevelop.Core + @@ -212,6 +221,18 @@ + + + + {92494904-35FA-4DC9-BDE9-3A3E87AC49D3} + Xwt + + + + {3F5B5BDA-69D5-441A-8142-AA25C998A997} + MonoDevelop.TextEditor + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtension.fs b/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtension.fs new file mode 100644 index 00000000000..ecf3ed98a9c --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtension.fs @@ -0,0 +1,276 @@ +namespace MonoDevelop.FSharp +open System +open System.Diagnostics +open System.Linq +open System.Threading + +open FSharp.Compiler.SourceCodeServices + +open Microsoft.CodeAnalysis.Text +open Microsoft.CodeAnalysis +open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.Text.Editor +open Microsoft.VisualStudio.Text +open Microsoft.VisualStudio.Threading + +open MonoDevelop.Components +open MonoDevelop.Core +open MonoDevelop.Ide +open MonoDevelop.Ide.Gui.Content +open MonoDevelop.Projects + +module VSMacIcons = + /// Translates icon code that we get from F# language service into a MonoDevelop icon + let getIcon (navItem: FSharpNavigationDeclarationItem) = + match navItem.Kind with + | NamespaceDecl -> "md-name-space" + | _ -> + match navItem.Glyph with + | FSharpGlyph.Class -> "md-class" + | FSharpGlyph.Enum -> "md-enum" + | FSharpGlyph.Struct -> "md-struct" + | FSharpGlyph.ExtensionMethod -> "md-struct" + | FSharpGlyph.Delegate -> "md-delegate" + | FSharpGlyph.Interface -> "md-interface" + | FSharpGlyph.Module -> "md-module" + | FSharpGlyph.NameSpace -> "md-name-space" + | FSharpGlyph.Method -> "md-method" + | FSharpGlyph.OverridenMethod -> "md-method" + | FSharpGlyph.Property -> "md-property" + | FSharpGlyph.Event -> "md-event" + | FSharpGlyph.Constant -> "md-field" + | FSharpGlyph.EnumMember -> "md-field" + | FSharpGlyph.Exception -> "md-exception" + | FSharpGlyph.Typedef -> "md-class" + | FSharpGlyph.Type -> "md-type" + | FSharpGlyph.Union -> "md-type" + | FSharpGlyph.Variable -> "md-field" + | FSharpGlyph.Field -> "md-field" + | FSharpGlyph.Error -> "md-breakpint" + +type internal FSharpPathedDocumentExtension(projectInfoManager: FSharpProjectOptionsManager, checker: FSharpChecker, view: ITextView, joinableTaskContext: JoinableTaskContext) as x = + + let pathChanged = new Event<_,_>() + let mutable currentPath = [||] + let mutable subscriptions = ResizeArray() + let mutable caretSubscription = None + let mutable ownerProjects = ResizeArray() + let mutable lastOwnerProjects = ResizeArray() + let mutable registration: WorkspaceRegistration = null + + let textContainer = view.TextBuffer.AsTextContainer() + + let getRelatedDocuments(container: SourceTextContainer) = + let workspace = IdeApp.TypeSystemService.Workspace + let sol = workspace.CurrentSolution + let ids = workspace.GetRelatedDocumentIds(container) + + ids + |> Seq.map(fun id -> sol.GetDocument(id)) + |> Seq.filter (isNull >> not) + + let getActiveDocument() = + let workspace = IdeApp.TypeSystemService.Workspace + let id = workspace.GetDocumentIdInCurrentContext(textContainer) + workspace.CurrentSolution.GetDocument(id) |> Option.ofObj + + let workspaceChanged(_) = + ownerProjects.Clear() + match getActiveDocument() with + | Some activeDocument -> + let activeProj = IdeServices.TypeSystemService.GetMonoProject(activeDocument.Project) :?> DotNetProject + if activeProj <> null then + ownerProjects.Add activeProj + else + for document in textContainer |> getRelatedDocuments do + let dotnetProj = IdeServices.TypeSystemService.GetMonoProject(document.Project) :?> DotNetProject + if dotnetProj <> null && document.Project.Id <> activeDocument.Project.Id then + ownerProjects.Add dotnetProj + + | None -> () + + let getOpenDocumentInCurrentContextWithChanges(text: SourceText) = + let workspace = IdeApp.TypeSystemService.Workspace + let solution = workspace.CurrentSolution + let id = workspace.GetDocumentIdInCurrentContext(text.Container) + if id = null || not(solution.ContainsDocument(id)) then + null + else + // We update all linked files to ensure they are all in sync. Otherwise code might try to jump from + // one linked file to another and be surprised if the text is entirely different. + let allIds = workspace.GetRelatedDocumentIds(text.Container) + solution.WithDocumentText(allIds, text, PreservationMode.PreserveIdentity) + .GetDocument(id) + + let mutable lastSnapshot: ITextSnapshot = null + let mutable lastOffset = 0 + + let update(position: CaretPosition) = + let snapshot = position.BufferPosition.Snapshot + let offset = position.BufferPosition.Position + + if lastSnapshot = snapshot && lastOffset = offset && ownerProjects.SequenceEqual(lastOwnerProjects) then + () + else + lastSnapshot <- snapshot + lastOffset <- offset + lastOwnerProjects <- ownerProjects.ToList() + + let roslynDocument = snapshot.AsText() |> getOpenDocumentInCurrentContextWithChanges + if roslynDocument <> null then + x.Update(roslynDocument, position.BufferPosition.Position) + + + let caretPositionChanged (caretPositionChangedArgs: CaretPositionChangedEventArgs) = + update caretPositionChangedArgs.NewPosition + + let textBufferChanged(_args) = + update view.Caret.Position + + do + registration <- Microsoft.CodeAnalysis.Workspace.GetWorkspaceRegistration(textContainer) + subscriptions.Add (registration.WorkspaceChanged.Subscribe(workspaceChanged)) + subscriptions.Add (view.TextBuffer.PostChanged.Subscribe(textBufferChanged)) + subscriptions.Add (view.Caret.PositionChanged.Subscribe(caretPositionChanged)) + currentPath <- [| new PathEntry(GettextCatalog.GetString("No selection")) |] + workspaceChanged None + + member x.GetEntityMarkup(node: FSharpNavigationDeclarationItem) = + let name = node.Name.Split('.') + if name.Length > 0 then name.Last() + else node.Name + + member x.GetNavigationItems(document:Document, fsSourceText) = + asyncMaybe { + let! parsingOptions, _options = projectInfoManager.TryGetOptionsByProject(document.Project, CancellationToken.None) + + let! parseResults = checker.ParseFile(document.FilePath, fsSourceText, parsingOptions) |> liftAsync + + try + return parseResults.GetNavigationItems().Declarations + with _ -> + Debug.Assert(false, "couldn't update navigation items, ignoring") + return [| |] + } + + member val SourceText : SourceText = null with get, set + + member private x.Update(document:Document, caretOffset) = + let caretLocation = TextSpan(caretOffset, 1) + + asyncMaybe { + let! sourceText = document.GetTextAsync(CancellationToken.None) |> liftTaskAsync + x.SourceText <- sourceText + let fsSourceText = sourceText.ToFSharpSourceText() + let! toplevel = x.GetNavigationItems(document, fsSourceText) + + let topLevelTypesInsideCursor = + toplevel + |> Array.filter (fun tl -> let range = tl.Declaration.Range + let declLocation = RoslynHelpers.FSharpRangeToTextSpan(sourceText, range) + caretLocation.IntersectsWith(declLocation)) + |> Array.sortBy(fun xs -> xs.Declaration.Range.StartLine) + + let newPath = ResizeArray<_>() + + let paths = + [ for top in topLevelTypesInsideCursor do + let name = top.Declaration.Name + let navitems = + if name.Contains(".") then + let nameparts = name.[.. name.LastIndexOf(".")] + toplevel |> Array.filter (fun decl -> decl.Declaration.Name.StartsWith(nameparts)) + else toplevel + yield (Some top.Declaration, (upcast navitems : obj)) + + if topLevelTypesInsideCursor.Length > 0 then + let lastToplevel = topLevelTypesInsideCursor.Last() + //only first child found is returned, could there be multiple children found? + let child = + lastToplevel.Nested + |> Array.tryFind (fun tl -> let range = RoslynHelpers.FSharpRangeToTextSpan(sourceText, tl.Range) + caretLocation.IntersectsWith(range)) + match child with + | Some c -> yield (Some c, upcast lastToplevel) + | None -> yield (None, upcast lastToplevel) ] + let previousPath = currentPath + + Runtime.RunInMainThread(fun() -> + paths |> List.iter(fun (declItemOption, tag) -> + match declItemOption with + | Some declItem -> + newPath.Add(new PathEntry(icon = ImageService.GetIcon(VSMacIcons.getIcon declItem, Gtk.IconSize.Menu), + markup =x.GetEntityMarkup(declItem), + Tag = tag)) + | None -> + newPath.Add(new PathEntry("No selection", Tag = tag))) + + let samePath = Seq.forall2 (fun (p1:PathEntry) (p2:PathEntry) -> p1.Markup = p2.Markup) previousPath newPath + + //ensure the path has changed from the previous one before setting and raising event. + if not samePath then + if newPath.Count = 0 then currentPath <- [|new PathEntry("No selection", Tag = null)|] + else currentPath <- newPath.ToArray() + + //invoke pathChanged + pathChanged.Trigger(x, DocumentPathChangedEventArgs(previousPath))) |> ignore + } + |> Async.Ignore + |> Async.Start + + interface IDisposable with + override x.Dispose() = + for disposable in subscriptions do disposable.Dispose() + subscriptions.Clear() + + interface IPathedDocument with + member x.CurrentPath = currentPath + member x.CreatePathWidget(index) = + let path = (x :> IPathedDocument).CurrentPath + if path = null || index < 0 || index >= path.Length then null else + let tag = path.[index].Tag + let window = new DropDownBoxListWindow(FSharpDataProvider(x, tag, view), FixedRowHeight=22, MaxVisibleRows=14) + window.SelectItem (path.[index].Tag) + MonoDevelop.Components.Control.op_Implicit window + + member x.add_PathChanged(handler) = pathChanged.Publish.AddHandler(handler) + member x.remove_PathChanged(handler) = pathChanged.Publish.RemoveHandler(handler) + +and internal FSharpDataProvider(ext:FSharpPathedDocumentExtension, tag, view: ITextView) = + let memberList = ResizeArray<_>() + + let reset() = + memberList.Clear() + match tag with + | :? array as navitems -> + for decl in navitems do + memberList.Add(decl.Declaration) + | :? FSharpNavigationTopLevelDeclaration as tld -> + memberList.AddRange(tld.Nested) + | _ -> () + + do reset() + + interface DropDownBoxListWindow.IListDataProvider with + member x.IconCount = + memberList.Count + + member x.Reset() = reset() + + member x.GetTag (n) = + memberList.[n] :> obj + + member x.ActivateItem(n) = + let node = memberList.[n] + let pos = RoslynHelpers.FSharpRangeToTextSpan(ext.SourceText, node.Range).Start + let point = new SnapshotPoint(view.TextSnapshot, pos) + view.Caret.MoveTo(point) |> ignore + + member x.GetMarkup(n) = + let node = memberList.[n] + ext.GetEntityMarkup (node) + + member x.GetIcon(n) = + let node = memberList.[n] + ImageService.GetIcon(VSMacIcons.getIcon node, Gtk.IconSize.Menu) + diff --git a/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtensionProvider.fs b/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtensionProvider.fs new file mode 100644 index 00000000000..140eacf595a --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtensionProvider.fs @@ -0,0 +1,50 @@ +namespace MonoDevelop.FSharp +// +// FSharpPathedDocumentExtensionProvider.fs +// +// Author: +// jasonimison +// +// Copyright (c) 2020 Microsoft. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +open System.ComponentModel.Composition +open Microsoft.VisualStudio.Text.Editor +open Microsoft.VisualStudio.Utilities +open MonoDevelop.TextEditor +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.Threading + +[)>] +[] +[] +[] +type internal FSharpPathedDocumentExtensionProvider + [] + ( + fsharpCheckerProvider: FSharpCheckerProvider, + optionsManager: FSharpProjectOptionsManager, + joinableTaskContext: JoinableTaskContext + ) as x = + inherit EditorContentInstanceProvider() + + override x.CreateInstance(view) = new FSharpPathedDocumentExtension(optionsManager, fsharpCheckerProvider.Checker, view, joinableTaskContext) From ae6ab31f469ddc3f64bba8f8f95901a863668e3b Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 4 Mar 2020 15:00:15 +0000 Subject: [PATCH 044/101] Add document outline pad --- .../src/FSharp.Editor/Common/Extensions.fs | 6 + .../src/FSharp.Editor/FSharp.Editor.fsproj | 6 + .../VSMac/FSharpOutlineDocumentExtension.fs | 186 ++++++++++++++++++ .../FSharpOutlineDocumentExtensionProvider.fs | 50 +++++ .../VSMac/FSharpPathedDocumentExtension.fs | 7 +- 5 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtension.fs create mode 100644 vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtensionProvider.fs diff --git a/vsintegration/src/FSharp.Editor/Common/Extensions.fs b/vsintegration/src/FSharp.Editor/Common/Extensions.fs index d17dcfd79ba..0dd50d968a3 100644 --- a/vsintegration/src/FSharp.Editor/Common/Extensions.fs +++ b/vsintegration/src/FSharp.Editor/Common/Extensions.fs @@ -250,6 +250,12 @@ module Option = else None + let inline tryCast<'T> (o: obj): 'T option = + match o with + | null -> None + | :? 'T as a -> Some a + | _ -> None + [] module Seq = open System.Collections.Immutable diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index df1b2e80eb1..6d24b44c75f 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -233,6 +233,12 @@ MonoDevelop.TextEditor + + + + {2C24D515-4A2C-445C-8419-C09231913CFA} + MonoDevelop.DesignerSupport + diff --git a/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtension.fs b/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtension.fs new file mode 100644 index 00000000000..0bd491fe30d --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtension.fs @@ -0,0 +1,186 @@ +namespace MonoDevelop.FSharp + +open System +open System.Diagnostics + +open FSharp.Compiler.SourceCodeServices +open Gtk +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.Text +open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.Text +open Microsoft.VisualStudio.Text.Editor +open Microsoft.VisualStudio.Threading + +open MonoDevelop.Components +open MonoDevelop.Core +open MonoDevelop.DesignerSupport +open MonoDevelop.Ide +open MonoDevelop.Ide.Gui.Components + +type internal FSharpOutlineDocumentExtension(projectInfoManager: FSharpProjectOptionsManager, checker: FSharpChecker, view: ITextView, joinableTaskContext: JoinableTaskContext) as x = + let mutable treeView : PadTreeView option = None + let mutable refreshingOutline : bool = false + let mutable timerId : uint32 = 0u + + let mutable subscriptions = ResizeArray() + + let textContainer = view.TextBuffer.AsTextContainer() + + let registration = Workspace.GetWorkspaceRegistration(textContainer) + do + subscriptions.Add (registration.WorkspaceChanged.Subscribe(x.UpdateDocumentOutline)) + subscriptions.Add (view.TextBuffer.PostChanged.Subscribe(x.UpdateDocumentOutline)) + subscriptions.Add (view.Caret.PositionChanged.Subscribe(x.UpdateDocumentOutline)) + + let getOpenDocumentInCurrentContextWithChanges(text: SourceText) = + let workspace = IdeApp.TypeSystemService.Workspace + let solution = workspace.CurrentSolution + let id = workspace.GetDocumentIdInCurrentContext(text.Container) + if id = null || not(solution.ContainsDocument(id)) then + null + else + // We update all linked files to ensure they are all in sync. Otherwise code might try to jump from + // one linked file to another and be surprised if the text is entirely different. + let allIds = workspace.GetRelatedDocumentIds(text.Container) + solution.WithDocumentText(allIds, text, PreservationMode.PreserveIdentity) + .GetDocument(id) + + let getNavigationItems(document:Document, fsSourceText) = + asyncMaybe { + let! parsingOptions, _options = projectInfoManager.TryGetOptionsByProject(document.Project, Async.DefaultCancellationToken) + + let! parseResults = checker.ParseFile(document.FilePath, fsSourceText, parsingOptions) |> liftAsync + + try + return parseResults.GetNavigationItems().Declarations + with _ -> + Debug.Assert(false, "couldn't update navigation items, ignoring") + return [| |] + } + + let refillTree() = + match treeView with + | Some(treeView) -> + + Runtime.AssertMainThread() + refreshingOutline <- false + + if treeView.IsRealized then + asyncMaybe { + let sourceText = view.TextBuffer.CurrentSnapshot.AsText() + let document = getOpenDocumentInCurrentContextWithChanges sourceText + let fsSourceText = sourceText.ToFSharpSourceText() + let! navItems = getNavigationItems(document, fsSourceText) + Runtime.RunInMainThread(fun() -> + let treeStore = treeView.Model :?> TreeStore + treeStore.Clear() + let toplevel = navItems + |> Array.sortBy(fun xs -> xs.Declaration.Range.StartLine) + + for item in toplevel do + let iter = treeStore.AppendValues([| item.Declaration |]) + let children = item.Nested + |> Array.sortBy(fun xs -> xs.Range.StartLine) + + for nested in children do + treeStore.AppendValues(iter, [| nested |]) |> ignore + + treeView.ExpandAll() + timerId <- 0u) |> ignore + } + |> Async.Ignore + |> Async.Start + + Gdk.Threads.Leave() + | None -> () + + refreshingOutline <- false + false + + member private x.UpdateDocumentOutline _ = + if not refreshingOutline then + refreshingOutline <- true + timerId <- GLib.Timeout.Add (1000u, (fun _ -> refillTree())) + + interface IDisposable with + override x.Dispose() = + if timerId > 0u then + GLib.Source.Remove timerId |> ignore + for disposable in subscriptions do disposable.Dispose() + subscriptions.Clear() + timerId <- 0u + + interface IOutlinedDocument with + member x.GetOutlineWidget() = + match treeView with + | Some(treeView) -> treeView :> Widget + | None -> + let treeStore = new TreeStore(typedefof) + let padTreeView = new PadTreeView(treeStore, HeadersVisible = true) + + let setCellIcon _column (cellRenderer : CellRenderer) (treeModel : TreeModel) (iter : TreeIter) = + let pixRenderer = cellRenderer :?> CellRendererImage + treeModel.GetValue(iter, 0) + |> Option.tryCast + |> Option.iter(fun item -> + pixRenderer.Image <- ImageService.GetIcon(VSMacIcons.getIcon item.[0], Gtk.IconSize.Menu)) + + let setCellText _column (cellRenderer : CellRenderer) (treeModel : TreeModel) (iter : TreeIter) = + let renderer = cellRenderer :?> CellRendererText + treeModel.GetValue(iter, 0) + |> Option.tryCast + |> Option.iter(fun item -> renderer.Text <- item.[0].Name) + + let jumpToDeclaration focus = + let iter : TreeIter ref = ref Unchecked.defaultof<_> + if padTreeView.Selection.GetSelected(iter) then + padTreeView.Model.GetValue(!iter, 0) + |> Option.tryCast + |> Option.iter(fun item -> + let sourceText = view.TextBuffer.CurrentSnapshot.AsText() + let node = item.[0] + let pos = RoslynHelpers.FSharpRangeToTextSpan(sourceText, node.Range).Start + let point = new SnapshotPoint(view.TextSnapshot, pos) + view.Caret.MoveTo(point) |> ignore + view.ViewScroller.EnsureSpanVisible(new SnapshotSpan(view.Caret.Position.BufferPosition, 0), EnsureSpanVisibleOptions.AlwaysCenter)) + + if focus then + view + |> Option.tryCast + |> Option.iter(fun view -> view.Focus()) + + treeView <- Some padTreeView + + let pixRenderer = new CellRendererImage(Xpad = 0u, Ypad = 0u) + padTreeView.TextRenderer.Xpad <- 0u + padTreeView.TextRenderer.Ypad <- 0u + + let treeCol = new TreeViewColumn() + treeCol.PackStart(pixRenderer, false) + treeCol.SetCellDataFunc(pixRenderer, new TreeCellDataFunc(setCellIcon)) + treeCol.PackStart(padTreeView.TextRenderer, true) + treeCol.SetCellDataFunc(padTreeView.TextRenderer, new TreeCellDataFunc(setCellText)) + + padTreeView.AppendColumn treeCol |> ignore + subscriptions.Add(padTreeView.Realized.Subscribe(fun _ -> refillTree |> ignore)) + subscriptions.Add(padTreeView.Selection.Changed.Subscribe(fun _ -> jumpToDeclaration false)) + subscriptions.Add(padTreeView.RowActivated.Subscribe(fun _ -> jumpToDeclaration true)) + + let sw = new CompactScrolledWindow() + sw.Add padTreeView + sw.ShowAll() + sw :> Widget + + member x.GetToolbarWidgets() = [] :> _ + + member x.ReleaseOutlineWidget() = + treeView |> Option.iter(fun tv -> + Option.tryCast(tv.Parent) + |> Option.iter (fun sw -> sw.Destroy()) + + match tv.Model with + :? TreeStore as ts -> ts.Dispose() + | _ -> ()) + + treeView <- None diff --git a/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtensionProvider.fs b/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtensionProvider.fs new file mode 100644 index 00000000000..0220a57923d --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtensionProvider.fs @@ -0,0 +1,50 @@ +namespace MonoDevelop.FSharp +// +// FSharpPathedDocumentExtensionProvider.fs +// +// Author: +// jasonimison +// +// Copyright (c) 2020 Microsoft. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +open System.ComponentModel.Composition +open Microsoft.VisualStudio.Text.Editor +open Microsoft.VisualStudio.Utilities +open MonoDevelop.TextEditor +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.Threading + +[)>] +[] +[] +[] +type internal FSharpOutlineDocumentExtensionProvider + [] + ( + fsharpCheckerProvider: FSharpCheckerProvider, + optionsManager: FSharpProjectOptionsManager, + joinableTaskContext: JoinableTaskContext + ) as x = + inherit EditorContentInstanceProvider() + + override x.CreateInstance(view) = new FSharpOutlineDocumentExtension(optionsManager, fsharpCheckerProvider.Checker, view, joinableTaskContext) diff --git a/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtension.fs b/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtension.fs index ecf3ed98a9c..9d183f21672 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtension.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtension.fs @@ -53,7 +53,6 @@ type internal FSharpPathedDocumentExtension(projectInfoManager: FSharpProjectOpt let pathChanged = new Event<_,_>() let mutable currentPath = [||] let mutable subscriptions = ResizeArray() - let mutable caretSubscription = None let mutable ownerProjects = ResizeArray() let mutable lastOwnerProjects = ResizeArray() let mutable registration: WorkspaceRegistration = null @@ -142,7 +141,7 @@ type internal FSharpPathedDocumentExtension(projectInfoManager: FSharpProjectOpt member x.GetNavigationItems(document:Document, fsSourceText) = asyncMaybe { - let! parsingOptions, _options = projectInfoManager.TryGetOptionsByProject(document.Project, CancellationToken.None) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsByProject(document.Project, Async.DefaultCancellationToken) let! parseResults = checker.ParseFile(document.FilePath, fsSourceText, parsingOptions) |> liftAsync @@ -159,7 +158,7 @@ type internal FSharpPathedDocumentExtension(projectInfoManager: FSharpProjectOpt let caretLocation = TextSpan(caretOffset, 1) asyncMaybe { - let! sourceText = document.GetTextAsync(CancellationToken.None) |> liftTaskAsync + let! sourceText = document.GetTextAsync(Async.DefaultCancellationToken) |> liftTaskAsync x.SourceText <- sourceText let fsSourceText = sourceText.ToFSharpSourceText() let! toplevel = x.GetNavigationItems(document, fsSourceText) @@ -225,6 +224,7 @@ type internal FSharpPathedDocumentExtension(projectInfoManager: FSharpProjectOpt interface IPathedDocument with member x.CurrentPath = currentPath + member x.CreatePathWidget(index) = let path = (x :> IPathedDocument).CurrentPath if path = null || index < 0 || index >= path.Length then null else @@ -265,6 +265,7 @@ and internal FSharpDataProvider(ext:FSharpPathedDocumentExtension, tag, view: IT let pos = RoslynHelpers.FSharpRangeToTextSpan(ext.SourceText, node.Range).Start let point = new SnapshotPoint(view.TextSnapshot, pos) view.Caret.MoveTo(point) |> ignore + view.ViewScroller.EnsureSpanVisible(new SnapshotSpan(view.Caret.Position.BufferPosition, 0), EnsureSpanVisibleOptions.AlwaysCenter); member x.GetMarkup(n) = let node = memberList.[n] From afcee8e16316745a36b3d4d06758571063c282ba Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 4 Mar 2020 20:48:53 +0000 Subject: [PATCH 045/101] Document outline fix --- .../VSMac/FSharpOutlineDocumentExtension.fs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtension.fs b/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtension.fs index 0bd491fe30d..44c74ef13fc 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtension.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtension.fs @@ -28,10 +28,6 @@ type internal FSharpOutlineDocumentExtension(projectInfoManager: FSharpProjectOp let textContainer = view.TextBuffer.AsTextContainer() let registration = Workspace.GetWorkspaceRegistration(textContainer) - do - subscriptions.Add (registration.WorkspaceChanged.Subscribe(x.UpdateDocumentOutline)) - subscriptions.Add (view.TextBuffer.PostChanged.Subscribe(x.UpdateDocumentOutline)) - subscriptions.Add (view.Caret.PositionChanged.Subscribe(x.UpdateDocumentOutline)) let getOpenDocumentInCurrentContextWithChanges(text: SourceText) = let workspace = IdeApp.TypeSystemService.Workspace @@ -69,7 +65,7 @@ type internal FSharpOutlineDocumentExtension(projectInfoManager: FSharpProjectOp if treeView.IsRealized then asyncMaybe { let sourceText = view.TextBuffer.CurrentSnapshot.AsText() - let document = getOpenDocumentInCurrentContextWithChanges sourceText + let! document = getOpenDocumentInCurrentContextWithChanges sourceText |> Option.ofObj let fsSourceText = sourceText.ToFSharpSourceText() let! navItems = getNavigationItems(document, fsSourceText) Runtime.RunInMainThread(fun() -> @@ -98,11 +94,16 @@ type internal FSharpOutlineDocumentExtension(projectInfoManager: FSharpProjectOp refreshingOutline <- false false - member private x.UpdateDocumentOutline _ = + let updateDocumentOutline _ = if not refreshingOutline then refreshingOutline <- true timerId <- GLib.Timeout.Add (1000u, (fun _ -> refillTree())) + do + subscriptions.Add (registration.WorkspaceChanged.Subscribe(updateDocumentOutline)) + subscriptions.Add (view.TextBuffer.PostChanged.Subscribe(updateDocumentOutline)) + updateDocumentOutline None + interface IDisposable with override x.Dispose() = if timerId > 0u then From 4694b6bd93bc3f516ac1e435fefd89b81e6e0059 Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 6 Mar 2020 20:45:48 +0000 Subject: [PATCH 046/101] rebase and add Microsoft.CodeAnalysis.ExternalAccess.FSharp --- .../BraceCompletionSessionProvider.fs | 3 +- .../src/FSharp.Editor/Common/Extensions.fs | 6 ++-- .../src/FSharp.Editor/Common/Logging.fs | 4 --- .../AsyncCompletionCommitManager.fs | 5 ++- .../Completion/CompletionProvider.fs | 2 +- .../Completion/CompletionService.fs | 14 ++++----- .../FSharp.Editor/Completion/SignatureHelp.fs | 4 +-- .../DocComments/XMLDocumentation.fs | 4 +-- .../src/FSharp.Editor/FSharp.Editor.fsproj | 31 +++++++++++++------ .../LanguageService/FSharpContentType.fs | 26 ++++++---------- .../FSharpProjectOptionsManager.fs | 6 ++-- .../LanguageService/LanguageService.fs | 10 +++--- .../Navigation/FindUsagesService.fs | 3 -- .../Navigation/GoToDefinitionService.fs | 8 ++--- .../Navigation/NavigableSymbolsService.fs | 15 +++++---- .../src/FSharp.Editor/QuickInfo/Navigation.fs | 1 - .../QuickInfo/QuickInfoProvider.fs | 9 ++---- .../FSharpOutlineDocumentExtensionProvider.fs | 5 ++- .../FSharpPathedDocumentExtensionProvider.fs | 5 ++- 19 files changed, 73 insertions(+), 88 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/AutomaticCompletion/BraceCompletionSessionProvider.fs b/vsintegration/src/FSharp.Editor/AutomaticCompletion/BraceCompletionSessionProvider.fs index dd3be821094..ac2308226c7 100644 --- a/vsintegration/src/FSharp.Editor/AutomaticCompletion/BraceCompletionSessionProvider.fs +++ b/vsintegration/src/FSharp.Editor/AutomaticCompletion/BraceCompletionSessionProvider.fs @@ -12,7 +12,6 @@ open Microsoft.VisualStudio.Text.BraceCompletion open Microsoft.VisualStudio.Text.Operations open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor -open Microsoft.VisualStudio.Utilities open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.Host @@ -504,7 +503,7 @@ type EditorBraceCompletionSessionFactory() = null [)>] -[] +[] [] [] [] diff --git a/vsintegration/src/FSharp.Editor/Common/Extensions.fs b/vsintegration/src/FSharp.Editor/Common/Extensions.fs index 0dd50d968a3..ccceaac719c 100644 --- a/vsintegration/src/FSharp.Editor/Common/Extensions.fs +++ b/vsintegration/src/FSharp.Editor/Common/Extensions.fs @@ -14,7 +14,7 @@ open FSharp.Compiler.SourceCodeServices open MonoDevelop.Core type private FSharpGlyph = FSharp.Compiler.SourceCodeServices.FSharpGlyph -type private FSharpRoslynGlyph = Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpGlyph +//type private FSharpRoslynGlyph = Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpGlyph module LoggingService = let inline private log f = Printf.kprintf f @@ -141,10 +141,9 @@ module private SourceText = sourceText type SourceText with - member this.ToFSharpSourceText() = SourceText.weakTable.GetValue(this, Runtime.CompilerServices.ConditionalWeakTable<_,_>.CreateValueCallback(SourceText.create)) - +(* type FSharpNavigationDeclarationItem with member x.RoslynGlyph : FSharpRoslynGlyph = match x.Glyph with @@ -217,6 +216,7 @@ type FSharpNavigationDeclarationItem with | Some SynAccess.Internal -> FSharpRoslynGlyph.ExtensionMethodInternal | _ -> FSharpRoslynGlyph.ExtensionMethodPublic | FSharpGlyph.Error -> FSharpRoslynGlyph.Error +*) [] module String = diff --git a/vsintegration/src/FSharp.Editor/Common/Logging.fs b/vsintegration/src/FSharp.Editor/Common/Logging.fs index 2c20eb965d6..6a754a304ef 100644 --- a/vsintegration/src/FSharp.Editor/Common/Logging.fs +++ b/vsintegration/src/FSharp.Editor/Common/Logging.fs @@ -1,10 +1,6 @@ namespace Microsoft.VisualStudio.FSharp.Editor.Logging open System -open System.Diagnostics -open System.ComponentModel.Composition -open Microsoft.VisualStudio.Shell -open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.FSharp.Editor open MonoDevelop.Core diff --git a/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManager.fs b/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManager.fs index b75bcebe680..f35f47deff4 100644 --- a/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManager.fs +++ b/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManager.fs @@ -73,12 +73,11 @@ type FSharpAsyncCompletionCommitManager() = open System.Composition open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion -open Microsoft.VisualStudio.Utilities open Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.Text.Editor [)>] -[] -[] +[] +[] //[] //[] type internal FSharpAsyncCompletionCommitManagerProvider3 diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index 28ad4b3bad0..e85f141f330 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -14,7 +14,7 @@ open Microsoft.CodeAnalysis.Options open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion -open Microsoft.VisualStudio.Shell +//open Microsoft.VisualStudio.Shell open FSharp.Compiler open FSharp.Compiler.Range diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index 50c832f0bea..c5bbcb5f88a 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -13,7 +13,7 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion -open Microsoft.VisualStudio.Shell +//open Microsoft.VisualStudio.Shell open System open System.ComponentModel.Composition @@ -22,7 +22,7 @@ open Microsoft.CodeAnalysis.Editor.Shared.Utilities open Microsoft.CodeAnalysis.Host.Mef open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion open Microsoft.VisualStudio.Text.Editor -open Microsoft.VisualStudio.Utilities +//open Microsoft.VisualStudio.Utilities open System.Threading.Tasks open System; @@ -446,8 +446,8 @@ type internal FSharpCompletionSource [)>] [)>] -[] -[] +[] +[] type internal CompletionSourceProvider [] ( @@ -468,12 +468,12 @@ type internal CompletionSourceProvider open System.Composition open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion -open Microsoft.VisualStudio.Utilities +//open Microsoft.VisualStudio.Utilities open Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.Text.Editor [)>] -[] -[] +[] +[] //[] //[] type internal FSharpAsyncCompletionCommitManagerProvider diff --git a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs index 460e39d1575..2e69221321b 100644 --- a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs +++ b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs @@ -12,8 +12,8 @@ open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.ExternalAccess.FSharp.SignatureHelp open Microsoft.VisualStudio.Text -open Microsoft.VisualStudio.Shell -open Microsoft.VisualStudio.Shell.Interop +////open Microsoft.VisualStudio.Shell +//open Microsoft.VisualStudio.Shell.Interop open FSharp.Compiler.Layout open FSharp.Compiler.Range diff --git a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs index be060a80030..57260553620 100644 --- a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs +++ b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs @@ -5,8 +5,8 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System open System.Runtime.CompilerServices open System.Text.RegularExpressions -open Microsoft.VisualStudio.Shell -open Microsoft.VisualStudio.Shell.Interop +//open Microsoft.VisualStudio.Shell +//open Microsoft.VisualStudio.Shell.Interop open FSharp.Compiler.SourceCodeServices open FSharp.Compiler.Layout open FSharp.Compiler.Layout.TaggedTextOps diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 6d24b44c75f..15c607ee1e5 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -11,7 +11,7 @@ False False $(MDFrameworkVersion) - win + --warnon:1182 Program true @@ -110,7 +110,6 @@ - @@ -126,11 +125,11 @@ - + @@ -153,7 +152,6 @@ - @@ -211,15 +209,12 @@ MonoDevelop.Core - - - + - @@ -239,6 +234,24 @@ {2C24D515-4A2C-445C-8419-C09231913CFA} MonoDevelop.DesignerSupport + + + + {653121B5-A28B-4DA1-9D4E-EECA4CA4203B} + Microsoft.CodeAnalysis.ExternalAccess.FSharp + + + {D6B7E899-542A-4EAB-8F06-E737657B29DE} + CoreUtility + CoreUtility + + + diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs index ee4daa24d35..1c921c7afab 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs @@ -1,25 +1,17 @@ -namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal open System.ComponentModel.Composition open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor -open Microsoft.VisualStudio.Utilities +//open Microsoft.VisualStudio.Utilities open Microsoft.VisualStudio.Editor type FSharpContentTypeDefinitions() = - //let _x = 1 - //[] - ////[] - //[] - //[] - ////[] - //member val FSharpContentTypeDefinition: ContentTypeDefinition = null with get, set - [] - [] - [] - member val FSharpSignatureHelpContentTypeDefinition: ContentTypeDefinition = null with get, set + [] + [] + member val FSharpSignatureHelpContentTypeDefinition: Microsoft.VisualStudio.Utilities.ContentTypeDefinition = null with get, set [] - [] - [] - member val FSharpFileExtension: FileExtensionToContentTypeDefinition = null with get, set \ No newline at end of file + [] + [] + member val FSharpFileExtension: Microsoft.VisualStudio.Utilities.FileExtensionToContentTypeDefinition = null with get, set \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index ec54745a420..dfba96f39d2 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -14,12 +14,12 @@ open FSharp.Compiler.SourceCodeServices open Microsoft.VisualStudio open Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.LanguageServices -open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem +//open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem //open Microsoft.VisualStudio.Shell open System.Threading //open Microsoft.VisualStudio.Shell.Interop -open Microsoft.VisualStudio.LanguageServices.Implementation.TaskList -open Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices +//open Microsoft.VisualStudio.LanguageServices.Implementation.TaskList +//open Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices open MonoDevelop.FSharp open MonoDevelop.Ide open MonoDevelop.Ide.TypeSystem diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 5956801f0bf..390003cc4da 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -12,12 +12,12 @@ open FSharp.Compiler.SourceCodeServices open FSharp.NativeInterop open Microsoft.VisualStudio open Microsoft.VisualStudio.FSharp.Editor -open Microsoft.VisualStudio.LanguageServices -open Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService -open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem +//open Microsoft.VisualStudio.LanguageServices +//open Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService +//open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem //open Microsoft.VisualStudio.LanguageServices.ProjectSystem -open Microsoft.VisualStudio.Shell -open Microsoft.VisualStudio.Shell.Interop +//open Microsoft.VisualStudio.Shell +//open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.Text.Outlining open FSharp.NativeInterop open Microsoft.CodeAnalysis.ExternalAccess.FSharp diff --git a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs index ef64161c948..736928712f5 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs @@ -22,8 +22,6 @@ open Microsoft.CodeAnalysis.Editor open Microsoft.CodeAnalysis.Host.Mef open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor -open Microsoft.VisualStudio.Shell -open Microsoft.VisualStudio.Shell.Interop open System open System; open System.ComponentModel.Composition; @@ -34,7 +32,6 @@ open Microsoft.CodeAnalysis.Text; open Microsoft.VisualStudio.Commanding; open Microsoft.VisualStudio.Text; open Microsoft.VisualStudio.Text.Editor.Commanding.Commands; -open Microsoft.VisualStudio.Utilities; [)>] type internal FSharpFindUsagesService diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs index 3c246cbca97..41f7df14823 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs @@ -11,10 +11,7 @@ open Microsoft.CodeAnalysis.Editor open Microsoft.CodeAnalysis.Host.Mef open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor -open Microsoft.VisualStudio.Shell -open Microsoft.VisualStudio.Shell.Interop open System -open System; open System.ComponentModel.Composition; open Microsoft.CodeAnalysis.Editor.Shared.Extensions; open Microsoft.CodeAnalysis.Notification; @@ -23,11 +20,10 @@ open Microsoft.CodeAnalysis.Text; open Microsoft.VisualStudio.Commanding; open Microsoft.VisualStudio.Text; open Microsoft.VisualStudio.Text.Editor.Commanding.Commands; -open Microsoft.VisualStudio.Utilities; [)>] -[] -[] +[] +[] type internal FSharpGotoDefinitionCommandHandler [] ( diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs index bd9ceb04903..647f4498d30 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs @@ -14,9 +14,9 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Navigation open Microsoft.VisualStudio.Language.Intellisense open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor -open Microsoft.VisualStudio.Shell.Interop +//open Microsoft.VisualStudio.Shell.Interop //open Microsoft.VisualStudio.Utilities -open Microsoft.VisualStudio.Shell +//open Microsoft.VisualStudio.Shell open System.Composition open System.Threading open System.Threading.Tasks @@ -26,8 +26,8 @@ open Microsoft.CodeAnalysis.Editor open Microsoft.CodeAnalysis.Host.Mef open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor -open Microsoft.VisualStudio.Shell -open Microsoft.VisualStudio.Shell.Interop +//open Microsoft.VisualStudio.Shell +////open Microsoft.VisualStudio.Shell.Interop open System open System; open System.ComponentModel.Composition; @@ -38,7 +38,6 @@ open Microsoft.CodeAnalysis.Text; open Microsoft.VisualStudio.Commanding; open Microsoft.VisualStudio.Text; open Microsoft.VisualStudio.Text.Editor.Commanding.Commands; -open Microsoft.VisualStudio.Utilities; [] type internal FSharpNavigableSymbol(item: FSharpNavigableItem, span: SnapshotSpan, gtd: GoToDefinition, statusBar: StatusBar) = @@ -105,9 +104,9 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider disposed <- true [)>] -[] -[] -[] +[] +[] +[] type internal FSharpNavigableSymbolService [] ( diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/Navigation.fs b/vsintegration/src/FSharp.Editor/QuickInfo/Navigation.fs index 63a5041f3ea..943ba03da2f 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/Navigation.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/Navigation.fs @@ -9,7 +9,6 @@ open Microsoft.CodeAnalysis open FSharp.Compiler.SourceCodeServices open FSharp.Compiler.Range -open Microsoft.VisualStudio.Shell.Interop type internal QuickInfoNavigation ( diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index 6889bb58003..1dfa4210ca9 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -12,10 +12,7 @@ open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Text open Microsoft.VisualStudio.Language.Intellisense -open Microsoft.VisualStudio.Shell -open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.Text -open Microsoft.VisualStudio.Utilities open FSharp.Compiler.SourceCodeServices open FSharp.Compiler.Range @@ -267,9 +264,9 @@ type internal FSharpAsyncQuickInfoSource |> RoslynHelpers.StartAsyncAsTask cancellationToken [)>] -[] -[] -[] +[] +[] +[] type internal FSharpAsyncQuickInfoSourceProvider [] ( diff --git a/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtensionProvider.fs b/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtensionProvider.fs index 0220a57923d..b99ffa320f4 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtensionProvider.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/FSharpOutlineDocumentExtensionProvider.fs @@ -28,16 +28,15 @@ open System.ComponentModel.Composition open Microsoft.VisualStudio.Text.Editor -open Microsoft.VisualStudio.Utilities open MonoDevelop.TextEditor open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor open Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.Threading [)>] -[] +[] [] -[] +[] type internal FSharpOutlineDocumentExtensionProvider [] ( diff --git a/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtensionProvider.fs b/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtensionProvider.fs index 140eacf595a..37ea6ef8d07 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtensionProvider.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/FSharpPathedDocumentExtensionProvider.fs @@ -28,16 +28,15 @@ open System.ComponentModel.Composition open Microsoft.VisualStudio.Text.Editor -open Microsoft.VisualStudio.Utilities open MonoDevelop.TextEditor open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor open Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.Threading [)>] -[] +[] [] -[] +[] type internal FSharpPathedDocumentExtensionProvider [] ( From 82c57d649cc701cfda530b469316cbf44f066046 Mon Sep 17 00:00:00 2001 From: nosami Date: Sat, 7 Mar 2020 20:55:25 +0000 Subject: [PATCH 047/101] Source files should be listed under SourceFiles project option --- .../FSharp.Editor/Common/CompilerArguments.fs | 5 +- .../src/FSharp.Editor/Common/Logger.fs | 1 + .../src/FSharp.Editor/FSharp.Editor.fsproj | 73 ++++++++----------- .../FSharpProjectOptionsManager.fs | 16 ++-- 4 files changed, 43 insertions(+), 52 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs b/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs index fa53675522c..a2741ec61c4 100644 --- a/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs +++ b/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs @@ -208,14 +208,13 @@ module CompilerArguments = // TODO: This currently ignores escaping using "..." for arg in fsconfig.OtherFlags |> splitByChars [|' '|] do yield arg - yield! dashr - yield! (getCompiledFiles project)] + yield! dashr ] let generateProjectOptions (project:DotNetProject, projectAssemblyReferences: AssemblyReference seq, fsconfig:FSharpCompilerParameters, reqLangVersion, targetFramework, configSelector, shouldWrap) = let compilerOptions = generateCompilerOptions (project, projectAssemblyReferences, fsconfig, reqLangVersion, targetFramework, configSelector, shouldWrap) |> Array.ofSeq let loadedTimeStamp = DateTime.MaxValue // Not 'now', we don't want to force reloading { ProjectFileName = project.FileName.FullPath.ToString() - SourceFiles = [| |] + SourceFiles = [| yield! (getCompiledFiles project) |] Stamp = None OtherOptions = compilerOptions ReferencedProjects = [| |] diff --git a/vsintegration/src/FSharp.Editor/Common/Logger.fs b/vsintegration/src/FSharp.Editor/Common/Logger.fs index 03a507bf74a..e325474210a 100644 --- a/vsintegration/src/FSharp.Editor/Common/Logger.fs +++ b/vsintegration/src/FSharp.Editor/Common/Logger.fs @@ -2,6 +2,7 @@ namespace Microsoft.VisualStudio.FSharp.Editor +open System open System open System.Diagnostics.Tracing diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 15c607ee1e5..d60895db010 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -17,7 +17,7 @@ true $(MSBuildProjectDirectory)\..\..\..\build\bin\MonoDevelop.exe $(MSBuildProjectDirectory)\..\..\..\build\bin - portable + true ..\..\..\..\..\build\AddIns\FSharp.Editor 3 @@ -30,7 +30,7 @@ ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML - false + true ;RELEASE true true @@ -41,6 +41,8 @@ false + true + full false false false @@ -65,6 +67,12 @@ + + + ..\..\..\..\Xamarin.Mac.dll + False + + @@ -113,6 +121,7 @@ + @@ -125,11 +134,6 @@ - @@ -154,6 +158,7 @@ + @@ -188,15 +193,18 @@ PublicResXFileCodeGenerator FSharp.Editor.Designer.fs - - ..\..\..\..\Xamarin.Mac.dll - False - - - - {91DD5A2D-9FE3-4C3C-9253-876141874DAD} - Mono.Addins + + + + + + + + + + {7525BB88-6142-4A26-93B9-A30C6983390A} + MonoDevelop.Core @@ -204,20 +212,6 @@ MonoDevelop.Ide - - {7525BB88-6142-4A26-93B9-A30C6983390A} - MonoDevelop.Core - - - - - - - - - - - {92494904-35FA-4DC9-BDE9-3A3E87AC49D3} Xwt @@ -228,30 +222,27 @@ MonoDevelop.TextEditor - - + + {91DD5A2D-9FE3-4C3C-9253-876141874DAD} + Mono.Addins + + + {2C24D515-4A2C-445C-8419-C09231913CFA} MonoDevelop.DesignerSupport - - {653121B5-A28B-4DA1-9D4E-EECA4CA4203B} Microsoft.CodeAnalysis.ExternalAccess.FSharp {D6B7E899-542A-4EAB-8F06-E737657B29DE} - CoreUtility + CoreUtility CoreUtility - - + + diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index dfba96f39d2..d8f3e147e0b 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -259,7 +259,7 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) if ct.IsCancellationRequested then reply.Reply None else - //try + try if document.Project.Solution.Workspace.Kind = WorkspaceKind.MiscellaneousFiles then let! options = tryComputeOptionsByFile document ct reply.Reply options @@ -269,23 +269,23 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) else let! options = tryComputeOptions document.Project reply.Reply options - //with - //| _ -> - //reply.Reply None + with + | _ -> + reply.Reply None | FSharpProjectOptionsMessage.TryGetOptionsByProject(project, reply, ct) -> if ct.IsCancellationRequested then reply.Reply None else - //try + try if project.Solution.Workspace.Kind = WorkspaceKind.MiscellaneousFiles || project.Name = FSharpConstants.FSharpMiscellaneousFilesName then reply.Reply None else let! options = tryComputeOptions project reply.Reply options - //with - //| _ -> - //reply.Reply None + with + | _ -> + reply.Reply None | FSharpProjectOptionsMessage.ClearOptions(projectId) -> cache.Remove(projectId) |> ignore From c37156a97dce2ff1382efcdd7ea6d36df87ec155 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 9 Mar 2020 14:57:18 +0000 Subject: [PATCH 048/101] Fix compiler options --- .../src/FSharp.Editor/Common/CompilerArguments.fs | 13 +++++++++++++ .../src/FSharp.Editor/Common/Parameters.fs | 7 ++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs b/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs index a2741ec61c4..e274ce4e952 100644 --- a/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs +++ b/vsintegration/src/FSharp.Editor/Common/CompilerArguments.fs @@ -9,6 +9,8 @@ open System.IO open System.Reflection open System.Globalization open System.Runtime.Versioning +open System.Threading +open System.Threading.Tasks open MonoDevelop.Projects open MonoDevelop.Ide open MonoDevelop.Core.Assemblies @@ -139,6 +141,17 @@ module CompilerArguments = | None -> LoggingService.LogWarning(resolutionFailedMessage "FSharp.Core") | _ -> () // found them both, no action needed + let needsFacades = + projectReferences + |> Seq.exists(fun reference -> TaskUtil.WaitAndGetResult(SystemAssemblyService.RequiresFacadeAssembliesAsync(reference), Async.DefaultCancellationToken)) + + if needsFacades then + LoggingService.LogInfo("Found PCLv2 assembly."); + + let facades = project.TargetRuntime.FindFacadeAssembliesForPCL(project.TargetFramework) + for facade in facades do + yield "-r:" + wrapf(facade) + for file in projectReferences do yield "-r:" + wrapf(file) ] diff --git a/vsintegration/src/FSharp.Editor/Common/Parameters.fs b/vsintegration/src/FSharp.Editor/Common/Parameters.fs index d15056530c0..1204cb8fa9d 100644 --- a/vsintegration/src/FSharp.Editor/Common/Parameters.fs +++ b/vsintegration/src/FSharp.Editor/Common/Parameters.fs @@ -46,13 +46,18 @@ type FSharpCompilerParameters() = [] let mutable debugType = "portable" + let getPlatformTarget() = + match platformTarget with + | "AnyCPU" -> "anycpu" // AnyCPU isn't a valid platform for the F# compiler + | target -> target + member x.Optimize with get () = optimize and set v = optimize <- v member x.GenerateTailCalls with get () = generateTailCalls and set v = generateTailCalls <- v override x.NoStdLib with get () = noStdLib and set v = noStdLib <- v member x.DefineConstants with get () = defineConstants and set v = defineConstants <- v member x.OtherFlags with get () = otherFlags and set v = otherFlags <- v member x.DocumentationFile with get () = documentationFile and set v = documentationFile <- v - member x.PlatformTarget with get () = platformTarget and set v = platformTarget <- v + member x.PlatformTarget with get () = getPlatformTarget() and set v = platformTarget <- v member x.TreatWarningsAsErrors with get () = warnAsError and set v = warnAsError <- v member x.WarningLevel with get () = warningLevel and set v = warningLevel <- v member x.NoWarn with get () = nowarn and set v = nowarn <- v From 5c5fb05d9880c508d2bdedc7bce3250129ffa4bc Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 9 Mar 2020 14:57:34 +0000 Subject: [PATCH 049/101] Guard against empty Project options --- .../FSharpProjectOptionsManager.fs | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index d8f3e147e0b..c56598d855a 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -228,20 +228,17 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) //} - let projectOptions = projectOpts.Value - //let sourceFiles = projectOptions.OtherOptions.Where(fun o -> o.StartsWith("/")) - //let projectOptions = { projectOptions with SourceFiles = sourceFiles.ToArray() } - // This can happen if we didn't receive the callback from HandleCommandLineChanges yet. - //if Array.isEmpty projectOptions.SourceFiles then - // return None - //else - checkerProvider.Checker.InvalidateConfiguration(projectOptions, startBackgroundCompileIfAlreadySeen = false, userOpName = "computeOptions") - - let parsingOptions, _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions) - - cache.[projectId] <- (project, parsingOptions, projectOptions) - - return Some(parsingOptions, projectOptions) + return projectOpts |> Option.bind(fun opts -> + //let sourceFiles = projectOptions.OtherOptions.Where(fun o -> o.StartsWith("/")) + //let projectOptions = { projectOptions with SourceFiles = sourceFiles.ToArray() } + // This can happen if we didn't receive the callback from HandleCommandLineChanges yet. + if Array.isEmpty opts.SourceFiles then + None + else + checkerProvider.Checker.InvalidateConfiguration(opts, startBackgroundCompileIfAlreadySeen = false, userOpName = "computeOptions") + let parsingOptions, _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions(opts) + cache.[projectId] <- (project, parsingOptions, opts) + Some(parsingOptions, opts)) | true, (oldProject, parsingOptions, projectOptions) -> if isProjectInvalidated oldProject project settings then From c188d6f149e1e6e5df86d99aa39505e6f6fe016c Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 9 Mar 2020 16:22:46 +0000 Subject: [PATCH 050/101] Revert FCS version --- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index d60895db010..a091c8e1846 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -199,7 +199,7 @@ - + From 7c0cd7cd2ec87a276eecacf19b9b1b6e8f4a32c2 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 9 Mar 2020 18:34:43 +0000 Subject: [PATCH 051/101] Fix ctrl-space --- .../src/FSharp.Editor/Completion/CompletionProvider.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index e85f141f330..b583ccf555b 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -89,7 +89,7 @@ type internal FSharpCompletionProvider if trigger.Reason = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionTriggerReason.Deletion && intelliSenseOptions.ShowAfterCharIsDeleted then Char.IsLetterOrDigit(triggerChar) || triggerChar = '.' - elif not (trigger.Reason = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionTriggerReason.Insertion) then + elif not (trigger.Reason = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionTriggerReason.Insertion || trigger.Reason = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionTriggerReason.InvokeAndCommitIfUnique) then false else // Do not trigger completion if it's not single dot, i.e. range expression @@ -98,7 +98,7 @@ type internal FSharpCompletionProvider else let documentId, filePath, defines = getInfo() CompletionUtils.shouldProvideCompletion(documentId, filePath, defines, sourceText, triggerPosition) && - (triggerChar = '.' || (intelliSenseOptions.ShowAfterCharIsTyped && CompletionUtils.isStartingNewWord(sourceText, triggerPosition))) + (trigger.Reason = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionTriggerReason.InvokeAndCommitIfUnique || triggerChar = '.' || (intelliSenseOptions.ShowAfterCharIsTyped && CompletionUtils.isStartingNewWord(sourceText, triggerPosition))) static member ProvideCompletionsAsyncAux(completionSource: Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.IAsyncCompletionSource , checker: FSharpChecker, sourceText: SourceText, caretPosition: int, options: FSharpProjectOptions, filePath: string, From 319b3147cb2a4e3700541ef3b213741025853a47 Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 10 Mar 2020 06:06:35 +0000 Subject: [PATCH 052/101] CompletionService clean up --- .../AsyncCompletionCommitManager.fs | 21 --- .../Completion/CompletionService.fs | 152 +----------------- 2 files changed, 2 insertions(+), 171 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManager.fs b/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManager.fs index f35f47deff4..735ed7839d7 100644 --- a/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManager.fs +++ b/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManager.fs @@ -69,24 +69,3 @@ type FSharpAsyncCompletionCommitManager() = /// Token used to cancel this operation /// Instruction for the editor how to proceed after invoking this method. Default is override __.TryCommit(session, buffer, item, typedChar, token) = CommitResult.Unhandled - - -open System.Composition -open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion -open Microsoft.VisualStudio.FSharp.Editor -open Microsoft.VisualStudio.Text.Editor -[)>] -[] -[] -//[] -//[] -type internal FSharpAsyncCompletionCommitManagerProvider3 - [] - ( - checkerProvider: FSharpCheckerProvider - ) = - let x = 1 - interface IAsyncCompletionCommitManagerProvider with - member __.GetOrCreate(textView) = - System.Diagnostics.Trace.WriteLine("GetOrCreate FSharpAsyncCompletionCommitManager") - FSharpAsyncCompletionCommitManager() :> _ \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index c5bbcb5f88a..d237a964a98 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -7,84 +7,26 @@ open System.Collections.Immutable open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Completion -open Microsoft.CodeAnalysis.Host open Microsoft.CodeAnalysis.Host.Mef open Microsoft.CodeAnalysis.ExternalAccess.FSharp open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion - -//open Microsoft.VisualStudio.Shell - -open System open System.ComponentModel.Composition -open Microsoft.CodeAnalysis.Editor.Host -open Microsoft.CodeAnalysis.Editor.Shared.Utilities -open Microsoft.CodeAnalysis.Host.Mef open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion open Microsoft.VisualStudio.Text.Editor -//open Microsoft.VisualStudio.Utilities open System.Threading.Tasks -open System; open System.Collections.Generic; -open System.Collections.Immutable; -open System.Collections.Specialized; -open System.Linq; -open System.Runtime.CompilerServices; -open System.Threading; -open System.Threading.Tasks; open Microsoft.CodeAnalysis.Classification -open Microsoft.CodeAnalysis.Completion; -open Microsoft.CodeAnalysis.Completion.Providers; -open Microsoft.CodeAnalysis.Editor.Host; -open Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion; -open Microsoft.CodeAnalysis.Editor.Shared.Extensions; -open Microsoft.CodeAnalysis.Editor.Shared.Utilities; -open Microsoft.CodeAnalysis.Experiments; -open Microsoft.CodeAnalysis.LanguageServices; -open Microsoft.CodeAnalysis.PooledObjects; -open Microsoft.CodeAnalysis.Shared.Extensions; open Microsoft.CodeAnalysis.Text; -open Microsoft.CodeAnalysis.Text.Shared.Extensions; -open Microsoft.VisualStudio.Core.Imaging; -open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; open Microsoft.VisualStudio.Text; open Microsoft.VisualStudio.Text.Adornments; -open FSharp.Compiler -open FSharp.Compiler.Range open FSharp.Compiler.SourceCodeServices -open System.Collections.Generic; -open System.Collections.Immutable; -open System.Linq; -open System.Runtime.CompilerServices; -open System.Threading; -open System.Threading.Tasks; -open Microsoft.CodeAnalysis.Completion; -open Microsoft.CodeAnalysis.Completion.Providers; -open Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion; -open Microsoft.CodeAnalysis.Editor.Shared.Extensions; -open Microsoft.CodeAnalysis.Editor.Shared.Utilities; -open Microsoft.CodeAnalysis.Experiments; -open Microsoft.CodeAnalysis.LanguageServices; -open Microsoft.CodeAnalysis.PooledObjects; -open Microsoft.CodeAnalysis.Shared.Extensions; -open Microsoft.CodeAnalysis.Text; -open Microsoft.CodeAnalysis.Text.Shared.Extensions; -open Microsoft.VisualStudio.Core.Imaging; -open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; -open Microsoft.VisualStudio.Text; -open Microsoft.VisualStudio.Text.Adornments; -open Microsoft.VisualStudio.Text.Editor; -//open Microsoft.VisualStudio.Text.Editor; -//open AsyncCompletionData = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; -//open RoslynCompletionItem = Microsoft.CodeAnalysis.Completion.CompletionItem; -//open VSCompletionItem = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem; type internal FSharpCompletionService ( workspace: Workspace, - //serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider, @@ -115,46 +57,10 @@ type internal FSharpCompletionService .WithDismissIfLastCharacterDeleted(true) .WithDefaultEnterKeyRule(enterKeyRule) - -//[] -//[, FSharpConstants.FSharpLanguageName)>] -//type internal FSharpCompletionServiceFactory - //[] - //( - // //serviceProvider: SVsServiceProvider, - // checkerProvider: FSharpCheckerProvider - - //) - - //member x.TR = 1 - //interface ILanguageServiceFactory with - //member this.CreateLanguageService(hostLanguageServices: HostLanguageServices) : ILanguageService = - //upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, projectInfoManager, assemblyContentProvider, settings) - ////upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, new FSharpProjectOptionsManager(, assemblyContentProvider, settings) - - [] -//[, FSharpConstants.FSharpContentTypeName)>] [, FSharpConstants.FSharpContentTypeName)>] - -//type internal FSharpCompletionServiceFactory - //[] - //( - // //serviceProvider: SVsServiceProvider, - // checkerProvider: FSharpCheckerProvider, - - // projectInfoManager: FSharpProjectOptionsManager, - // assemblyContentProvider: AssemblyContentProvider, - // settings: EditorOptions - //) = - - //interface ILanguageServiceFactory with - //member this.CreateLanguageService(hostLanguageServices: HostLanguageServices) : ILanguageService = - //upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, projectInfoManager, assemblyContentProvider, settings) - ////upcast new FSharpCompletionService(hostLanguageServices.WorkspaceServices.Workspace, (*serviceProvider,*) checkerProvider, new FSharpProjectOptionsManager(, assemblyContentProvider, settings) - type internal FSharpCompletionSource - (textView: ITextView, checkerProvider, projectInfoManager, assemblyContentProvider) = + (textView: ITextView, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider) = let settings: EditorOptions = textView.TextBuffer.GetWorkspace().Services.GetService() @@ -308,12 +214,6 @@ type internal FSharpCompletionSource /// Location where completion will take place, on the view's data buffer: /// Cancellation token that may interrupt this operation /// A struct that holds completion items and applicable span - //Task GetExpandedCompletionContextAsync( - //IAsyncCompletionSession session, - //CompletionExpander expander, - //CompletionTrigger initialTrigger, - //SnapshotSpan applicableToSpan, - //CancellationToken token); let commitChars = [|' '; '='; ','; '.'; '<'; '>'; '('; ')'; '!'; ':'; '['; ']'; '|'|].ToImmutableArray() interface IAsyncExpandingCompletionSource with member __.GetExpandedCompletionContextAsync(session, expander, initialTrigger, applicableToSpan, token) = @@ -328,8 +228,6 @@ type internal FSharpCompletionSource let document = session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() let sourceText = session.TextView.TextSnapshot.AsText() - let provider = FSharpCompletionProvider(document.Project.Solution.Workspace, checkerProvider, projectInfoManager, assemblyContentProvider) - //let! completions = provider.ProvideCompletionsAsync(session.) |> Async.AwaitTask let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, token) match options with | Some (_parsingOptions, projectOptions) -> @@ -341,8 +239,6 @@ type internal FSharpCompletionSource session.TextView.Properties.["PotentialCommitCharacters"] <- commitChars - //static member ProvideCompletionsAsyncAux(checker: FSharpChecker, sourceText: SourceText, caretPosition: int, options: FSharpProjectOptions, filePath: string, - //textVersionHash: int, getAllSymbols: FSharpCheckFileResults -> AssemblySymbol list, languageServicePerformanceOptions: LanguageServicePerformanceOptions, intellisenseOptions: IntelliSenseOptions) = let! completions = FSharpCompletionProvider.ProvideCompletionsAsyncAux(this, checkerProvider.Checker, sourceText, triggerLocation.Position, projectOptions, document.FilePath, textVersion.GetHashCode(), getAllSymbols, settings.LanguageServicePerformance, settings.IntelliSense) match completions with | Some completions' -> @@ -353,23 +249,6 @@ type internal FSharpCompletionSource return Data.CompletionContext.Empty } |> RoslynHelpers.StartAsyncAsTask token - /// - /// Called once per completion session to fetch the set of all completion items available at a given location. - /// Called on a background thread. - /// - /// Reference to the active - /// What caused the completion - /// Location where completion was triggered, on the subject buffer that matches this 's content type - /// Location where completion will take place, on the view's data buffer: - /// Cancellation token that may interrupt this operation - /// A struct that holds completion items and applicable span - //Task GetCompletionContextAsync( - //IAsyncCompletionSession session, - //CompletionTrigger trigger, - //SnapshotPoint triggerLocation, - //SnapshotSpan applicableToSpan, - //CancellationToken token); - /// /// Returns tooltip associated with provided . /// The returned object will be rendered by . See its documentation for default supported types. @@ -380,7 +259,6 @@ type internal FSharpCompletionSource /// which is a subject of the tooltip /// Cancellation token that may interrupt this operation /// An object that will be passed to . See its documentation for supported types. - //Task GetDescriptionAsync(IAsyncCompletionSession session, CompletionItem item, CancellationToken token); member __.GetDescriptionAsync(session, item, token) = async { let document = session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() @@ -411,18 +289,13 @@ type internal FSharpCompletionSource /// Location on the subject buffer that matches this 's content type /// Cancellation token that may interrupt this operation /// Whether this wishes to participate in completion. - //CompletionStartData InitializeCompletion(CompletionTrigger trigger, SnapshotPoint triggerLocation, CancellationToken token); member __.InitializeCompletion(trigger, triggerLocation, token) = System.Diagnostics.Trace.WriteLine("initialize") - //Data.CompletionStartData.DoesNotParticipateInCompletion - //Data.CompletionStartData.ParticipatesInCompletionIfAny use _logBlock = Logger.LogBlock LogEditorFunctionId.Completion_ShouldTrigger let document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges() let getInfo() = - //let documentId = workspace.GetDocumentIdInCurrentContext(sourceText.Container) - //let document = workspace.CurrentSolution.GetDocument(documentId) let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) (document.Id, document.FilePath, defines) @@ -462,27 +335,6 @@ type internal CompletionSourceProvider new FSharpCompletionSource(textView, checkerProvider, projectInfoManager, assemblyContentProvider) :> _ interface IAsyncCompletionCommitManagerProvider with - member __.GetOrCreate(textView) = - System.Diagnostics.Trace.WriteLine("GetOrCreate FSharpAsyncCompletionCommitManager") - FSharpAsyncCompletionCommitManager() :> _ - -open System.Composition -open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion -//open Microsoft.VisualStudio.Utilities -open Microsoft.VisualStudio.FSharp.Editor -open Microsoft.VisualStudio.Text.Editor -[)>] -[] -[] -//[] -//[] -type internal FSharpAsyncCompletionCommitManagerProvider - [] - ( - checkerProvider: FSharpCheckerProvider - ) = - let x = 1 - interface IAsyncCompletionCommitManagerProvider with - member __.GetOrCreate(textView) = + member __.GetOrCreate(_textView) = System.Diagnostics.Trace.WriteLine("GetOrCreate FSharpAsyncCompletionCommitManager") FSharpAsyncCompletionCommitManager() :> _ From 67187594a75d29d5671a650b351ad5b8bc899e9b Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 19 Mar 2020 11:31:51 +0000 Subject: [PATCH 053/101] Color locals like C# --- vsintegration/src/FSharp.Editor/LanguageService/Tokenizer.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/Tokenizer.fs b/vsintegration/src/FSharp.Editor/LanguageService/Tokenizer.fs index e45e28a19d0..e5be644fc62 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/Tokenizer.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/Tokenizer.fs @@ -441,7 +441,7 @@ module internal Tokenizer = let compilerTokenToRoslynToken(colorKind: FSharpTokenColorKind) : string = match colorKind with | FSharpTokenColorKind.Comment -> ClassificationTypeNames.Comment - | FSharpTokenColorKind.Identifier -> ClassificationTypeNames.Identifier + | FSharpTokenColorKind.Identifier -> ClassificationTypeNames.LocalName | FSharpTokenColorKind.Keyword -> ClassificationTypeNames.Keyword | FSharpTokenColorKind.String -> ClassificationTypeNames.StringLiteral | FSharpTokenColorKind.Text -> ClassificationTypeNames.Text From 04fc5fae165c451fb29f697cfa120f6b575c0378 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 19 Mar 2020 11:32:14 +0000 Subject: [PATCH 054/101] Highlight mutable types --- .../ClassificationDefinition.fs | 27 +++++++++++++++++++ .../Classification/ClassificationService.fs | 5 +++- .../src/FSharp.Editor/FSharp.Editor.fsproj | 12 ++++----- 3 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/Classification/ClassificationDefinition.fs diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinition.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinition.fs new file mode 100644 index 00000000000..fc38a0b9eb4 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinition.fs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.VisualStudio.FSharp.Editor + +open Microsoft.VisualStudio.Text.Classification +open System.ComponentModel.Composition +open System +open System.Windows.Media +open Microsoft.VisualStudio.Language.StandardClassification + +module internal ClassificationDefinition = + [] + [] + [] + let FSharpMutableVarClassificationType : ClassificationTypeDefinition = null + +[)>] +[] +[] +[] +[] +type internal FSharpMutableVarTypeFormat() as self = + inherit EditorFormatDefinition() + + do self.DisplayName <- SR.FSharpMutableVarsClassificationType() + self.ForegroundColor <- Nullable(Color.FromRgb(255uy, 0uy, 0uy)) + diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs index c57451e46fd..1d8d3c6f1ef 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs @@ -14,6 +14,8 @@ open Microsoft.CodeAnalysis.Editor open Microsoft.CodeAnalysis.Host.Mef open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Classification +open Microsoft.VisualStudio.Text.Classification +open System.Windows.Media // IEditorClassificationService is marked as Obsolete, but is still supported. The replacement (IClassificationService) // is internal to Microsoft.CodeAnalysis.Workspaces which we don't have internals visible to. Rather than add yet another @@ -21,10 +23,11 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Classification #nowarn "44" open FSharp.Compiler.SourceCodeServices + [] module internal FSharpClassificationTypes = let [] Function = ClassificationTypeNames.MethodName// "Function"// "FSharp.Function" - let [] MutableVar = ClassificationTypeNames.LocalName// "FSharp.MutableVar" + let [] MutableVar = "mutable name" let [] Printf = ClassificationTypeNames.MethodName//"FSharp.Printf" let [] ReferenceType = ClassificationTypeNames.ClassName let [] Module = ClassificationTypeNames.ClassName //ModuleName diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index a091c8e1846..136c729478f 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -17,7 +17,8 @@ true $(MSBuildProjectDirectory)\..\..\..\build\bin\MonoDevelop.exe $(MSBuildProjectDirectory)\..\..\..\build\bin - + true + portable true ..\..\..\..\..\build\AddIns\FSharp.Editor 3 @@ -41,8 +42,6 @@ false - true - full false false false @@ -134,8 +133,9 @@ - + + @@ -198,7 +198,6 @@ - @@ -233,7 +232,7 @@ MonoDevelop.DesignerSupport - {653121B5-A28B-4DA1-9D4E-EECA4CA4203B} + {44A1C739-8C32-475E-BE92-F88332CE35AB} Microsoft.CodeAnalysis.ExternalAccess.FSharp @@ -243,6 +242,7 @@ + From 9b643f028b6dacf6801ccca4842cb068282e9b59 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 19 Mar 2020 11:46:29 +0000 Subject: [PATCH 055/101] Respect highlight mutables setting --- .../Classification/ClassificationService.fs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs index 1d8d3c6f1ef..5cc0ad56120 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs @@ -16,6 +16,7 @@ open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Classification open Microsoft.VisualStudio.Text.Classification open System.Windows.Media +open MonoDevelop.Core // IEditorClassificationService is marked as Obsolete, but is still supported. The replacement (IClassificationService) // is internal to Microsoft.CodeAnalysis.Workspaces which we don't have internals visible to. Rather than add yet another @@ -26,26 +27,30 @@ open FSharp.Compiler.SourceCodeServices [] module internal FSharpClassificationTypes = - let [] Function = ClassificationTypeNames.MethodName// "Function"// "FSharp.Function" + let [] Function = ClassificationTypeNames.MethodName let [] MutableVar = "mutable name" - let [] Printf = ClassificationTypeNames.MethodName//"FSharp.Printf" + let [] Printf = ClassificationTypeNames.MethodName let [] ReferenceType = ClassificationTypeNames.ClassName - let [] Module = ClassificationTypeNames.ClassName //ModuleName + let [] Module = ClassificationTypeNames.ClassName let [] ValueType = ClassificationTypeNames.StructName let [] Keyword = ClassificationTypeNames.Keyword let [] Enum = ClassificationTypeNames.EnumName - let [] Property = ClassificationTypeNames.PropertyName//"Property"// "FSharp.Property" + let [] Property = ClassificationTypeNames.PropertyName let [] Interface = ClassificationTypeNames.InterfaceName let [] TypeArgument = ClassificationTypeNames.TypeParameterName let [] Operator = ClassificationTypeNames.Operator - let [] Disposable = ClassificationTypeNames.ClassName// "FSharp.Disposable" + let [] Disposable = ClassificationTypeNames.ClassName let getClassificationTypeName = function | SemanticClassificationType.ReferenceType -> ReferenceType | SemanticClassificationType.Module -> Module | SemanticClassificationType.ValueType -> ValueType | SemanticClassificationType.Function -> Function - | SemanticClassificationType.MutableVar -> MutableVar + | SemanticClassificationType.MutableVar -> + if PropertyService.Get("FSharpBinding.HighlightMutables", false) then + MutableVar + else + ClassificationTypeNames.LocalName | SemanticClassificationType.Printf -> Printf | SemanticClassificationType.ComputationExpression | SemanticClassificationType.IntrinsicFunction -> Keyword From 20275946f4e0199264fb380a8e334040b239ad21 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 19 Mar 2020 13:28:09 +0000 Subject: [PATCH 056/101] Better default color --- .../FSharp.Editor/Classification/ClassificationDefinition.fs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinition.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinition.fs index fc38a0b9eb4..f373586fc87 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinition.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinition.fs @@ -23,5 +23,4 @@ type internal FSharpMutableVarTypeFormat() as self = inherit EditorFormatDefinition() do self.DisplayName <- SR.FSharpMutableVarsClassificationType() - self.ForegroundColor <- Nullable(Color.FromRgb(255uy, 0uy, 0uy)) - + self.ForegroundColor <- Nullable(Color.FromRgb(255uy, 210uy, 28uy)) \ No newline at end of file From fe6bf698b2acbb3b91260041f0860d69e0e6b640 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 19 Mar 2020 16:08:28 +0000 Subject: [PATCH 057/101] Don't local copy references --- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 136c729478f..262b2338d92 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -205,31 +205,37 @@ {7525BB88-6142-4A26-93B9-A30C6983390A} MonoDevelop.Core + False {27096E7F-C91C-4AC6-B289-6897A701DF21} MonoDevelop.Ide + False {92494904-35FA-4DC9-BDE9-3A3E87AC49D3} Xwt + False {3F5B5BDA-69D5-441A-8142-AA25C998A997} MonoDevelop.TextEditor + False {91DD5A2D-9FE3-4C3C-9253-876141874DAD} Mono.Addins + False {2C24D515-4A2C-445C-8419-C09231913CFA} MonoDevelop.DesignerSupport + False {44A1C739-8C32-475E-BE92-F88332CE35AB} From d1c841622cb999ab555337131f4f6bbe1ba831c1 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 23 Mar 2020 14:35:00 +0000 Subject: [PATCH 058/101] Share output folder with FSharpBinding --- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 262b2338d92..ec5d91945e2 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -20,7 +20,7 @@ true portable true - ..\..\..\..\..\build\AddIns\FSharp.Editor + ..\..\..\..\..\build\AddIns\FSharpBinding 3 ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML false From 645a29dc8e4f45731eacd9ea5cf2807b399f5dbb Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 26 Mar 2020 15:42:17 +0000 Subject: [PATCH 059/101] Implement IBreakpointSpanResolver for more granular breakpoints --- .../Debugging/BreakpointSpanResolver.fs | 89 +++++++++++++++++++ .../src/FSharp.Editor/FSharp.Editor.fsproj | 65 +++++++------- 2 files changed, 124 insertions(+), 30 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/Debugging/BreakpointSpanResolver.fs diff --git a/vsintegration/src/FSharp.Editor/Debugging/BreakpointSpanResolver.fs b/vsintegration/src/FSharp.Editor/Debugging/BreakpointSpanResolver.fs new file mode 100644 index 00000000000..64cae3275c7 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Debugging/BreakpointSpanResolver.fs @@ -0,0 +1,89 @@ +// +// BreakpointSpanResolver.fs +// +// Author: +// jasonimison +// +// Copyright (c) 2020 Microsoft +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace Microsoft.VisualStudio.FSharp.Editor + +open System +open System.Threading.Tasks + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.Text +open Microsoft.VisualStudio.Text + +open FSharp.Compiler.SourceCodeServices +open FSharp.Compiler.Range + +open MonoDevelop.Debugger +open MonoDevelop.Ide.Gui.Documents + +// The breakpoint span resolver is using Mono.Addins rather than MEF +[] +type internal BreakpointSpanResolver() = + inherit DocumentControllerExtension() + + static let userOpName = "BreakpointResolution" + + let getCheckerService(document: Document) = + document.Project.Solution.Workspace.Services.GetService() + + let fsharpRangeToSpan(sourceText: SourceText, range: range) = + let startPosition = sourceText.Lines.[max 0 (range.StartLine - 1)].Start + range.StartColumn + let endPosition = sourceText.Lines.[min (range.EndLine - 1) (sourceText.Lines.Count - 1)].Start + range.EndColumn + Span(startPosition, endPosition - startPosition) + + member x.SupportsController(controller: DocumentController) = + Task.FromResult(controller.GetContent() <> null) + + static member GetBreakpointLocation(checker: FSharpChecker, sourceText: SourceText, fileName: string, position: int, parsingOptions: FSharpParsingOptions) = + async { + let textLinePos = sourceText.Lines.GetLinePosition(position) + let textInLine = sourceText.GetSubText(sourceText.Lines.[textLinePos.Line].Span).ToString() + + if String.IsNullOrWhiteSpace textInLine then + return None + else + let textLineColumn = textLinePos.Character + let fcsTextLineNumber = Line.fromZ textLinePos.Line // Roslyn line numbers are zero-based, FSharp.Compiler.Service line numbers are 1-based + let! parseResults = checker.ParseFile(fileName, sourceText.ToFSharpSourceText(), parsingOptions, userOpName = userOpName) + return parseResults.ValidateBreakpointLocation(mkPos fcsTextLineNumber textLineColumn) + } + + interface IBreakpointSpanResolver with + member x.GetBreakpointSpanAsync(buffer, position, cancellationToken) = + let getLineSpan() = + buffer.CurrentSnapshot.GetLineFromPosition(max 0 (min position (buffer.CurrentSnapshot.Length - 1))).Extent.Span + + asyncMaybe { + let! document = buffer.CurrentSnapshot.GetRelatedDocumentsWithChanges() |> Seq.tryHead + let checkerService = getCheckerService document + let projectInfoManager = checkerService.FSharpProjectOptionsManager + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let sourceText = buffer.AsTextContainer().CurrentText + let! range = BreakpointSpanResolver.GetBreakpointLocation(checkerService.Checker, sourceText, document.Name, position, parsingOptions) + return fsharpRangeToSpan(sourceText, range) + } + |> Async.map (Option.defaultWith getLineSpan) + |> RoslynHelpers.StartAsyncAsTask cancellationToken diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index ec5d91945e2..abdaa4f2efc 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -139,8 +139,8 @@ - + @@ -198,57 +198,62 @@ - - - - - {7525BB88-6142-4A26-93B9-A30C6983390A} - MonoDevelop.Core + + + {D6B7E899-542A-4EAB-8F06-E737657B29DE} + CoreUtility + CoreUtility + + + {DFA822CA-CE06-4ECB-BA60-EB2A256E28F6} + Microsoft.CodeAnalysis.ExternalAccess.FSharp + + + {2C24D515-4A2C-445C-8419-C09231913CFA} + MonoDevelop.DesignerSupport + False + + + + {91DD5A2D-9FE3-4C3C-9253-876141874DAD} + Mono.Addins False + + {27096E7F-C91C-4AC6-B289-6897A701DF21} MonoDevelop.Ide False - - {92494904-35FA-4DC9-BDE9-3A3E87AC49D3} - Xwt + + {7525BB88-6142-4A26-93B9-A30C6983390A} + MonoDevelop.Core False + + + {3F5B5BDA-69D5-441A-8142-AA25C998A997} MonoDevelop.TextEditor False - - {91DD5A2D-9FE3-4C3C-9253-876141874DAD} - Mono.Addins + + {92494904-35FA-4DC9-BDE9-3A3E87AC49D3} + Xwt False - - - {2C24D515-4A2C-445C-8419-C09231913CFA} - MonoDevelop.DesignerSupport - False - - - {44A1C739-8C32-475E-BE92-F88332CE35AB} - Microsoft.CodeAnalysis.ExternalAccess.FSharp - - - {D6B7E899-542A-4EAB-8F06-E737657B29DE} - CoreUtility - CoreUtility + + {2357AABD-08C7-4808-A495-8FF2D3CDFDB0} + MonoDevelop.Debugger - - - + From 0cca372f67e8b47f0d8a36573cb0e692544461d7 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 30 Mar 2020 09:33:20 +0100 Subject: [PATCH 060/101] Simplify CompletionService --- .../Completion/CompletionService.fs | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index d237a964a98..ed19e75eff6 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -63,7 +63,7 @@ type internal FSharpCompletionSource (textView: ITextView, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider) = - let settings: EditorOptions = textView.TextBuffer.GetWorkspace().Services.GetService() + //let settings: EditorOptions = textView.TextBuffer.GetWorkspace().Services.GetService() let createParagraphFromLines(lines: List) = if lines.Count = 1 then @@ -233,13 +233,14 @@ type internal FSharpCompletionSource | Some (_parsingOptions, projectOptions) -> let! textVersion = document.GetTextVersionAsync(token) |> liftTaskAsync let getAllSymbols(fileCheckResults: FSharpCheckFileResults) = - if settings.IntelliSense.IncludeSymbolsFromUnopenedNamespacesOrModules - then assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies(fileCheckResults) - else [] + [] + //if settings.IntelliSense.IncludeSymbolsFromUnopenedNamespacesOrModules + //then assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies(fileCheckResults) + //else [] session.TextView.Properties.["PotentialCommitCharacters"] <- commitChars - let! completions = FSharpCompletionProvider.ProvideCompletionsAsyncAux(this, checkerProvider.Checker, sourceText, triggerLocation.Position, projectOptions, document.FilePath, textVersion.GetHashCode(), getAllSymbols, settings.LanguageServicePerformance, settings.IntelliSense) + let! completions = FSharpCompletionProvider.ProvideCompletionsAsyncAux(this, checkerProvider.Checker, sourceText, triggerLocation.Position, projectOptions, document.FilePath, textVersion.GetHashCode(), getAllSymbols, (*settings.LanguageServicePerformance*) LanguageServicePerformanceOptions.Default, (*settings.IntelliSense*) IntelliSenseOptions.Default) match completions with | Some completions' -> return new Data.CompletionContext(completions'.ToImmutableArray()) @@ -295,27 +296,24 @@ type internal FSharpCompletionSource let document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges() - let getInfo() = + let getInfo() = let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) (document.Id, document.FilePath, defines) - match document.TryGetText() with - | true, sourceText -> - let shouldTrigger = - FSharpCompletionProvider.ShouldTriggerCompletionAux(sourceText, triggerLocation.Position, trigger, getInfo, settings.IntelliSense) - - match shouldTrigger with - | false -> - Data.CompletionStartData.DoesNotParticipateInCompletion - | true -> - Data.CompletionStartData( - participation = Data.CompletionParticipation.ProvidesItems, - applicableToSpan = new SnapshotSpan( - triggerLocation.Snapshot, - CompletionUtils.getCompletionItemSpan sourceText triggerLocation.Position)) - | false, _ -> - Data.CompletionStartData.DoesNotParticipateInCompletion + let sourceText = triggerLocation.Snapshot.AsText() + let shouldTrigger = + FSharpCompletionProvider.ShouldTriggerCompletionAux(sourceText, triggerLocation.Position, trigger, getInfo, (*settings.IntelliSense*) IntelliSenseOptions.Default) + + match shouldTrigger with + | false -> + Data.CompletionStartData.DoesNotParticipateInCompletion + | true -> + Data.CompletionStartData( + participation = Data.CompletionParticipation.ProvidesItems, + applicableToSpan = new SnapshotSpan( + triggerLocation.Snapshot, + CompletionUtils.getCompletionItemSpan sourceText triggerLocation.Position)) [)>] [)>] From 3b82b155930d9afd506fcdcb22470cd38f09df63 Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 31 Mar 2020 11:41:29 +0100 Subject: [PATCH 061/101] Fix arg out of range exception --- vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs index 34655d81048..a3fc37d5ff8 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs @@ -144,7 +144,7 @@ module internal CompletionUtils = let rec findStart index = let c = sourceText.[index-1] match isIdentifierStartCharacter c with - | true when index > 0 -> + | true when index > 1 -> findStart (index-1) | _ -> index From d51d1acd2719ab0d7d83b971cb5ea117aa47ff00 Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 31 Mar 2020 11:41:52 +0100 Subject: [PATCH 062/101] Start converting F# interactive pad --- .../src/FSharp.Editor/FSharp.Editor.fsproj | 37 +++++++++++-------- .../src/FSharp.Editor/FSharp.addin.xml | 12 ++++++ 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index abdaa4f2efc..3a60789e66a 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -1,7 +1,7 @@  - + Debug AnyCPU @@ -11,7 +11,7 @@ False False $(MDFrameworkVersion) - + --warnon:1182 Program true @@ -141,6 +141,7 @@ + @@ -198,12 +199,6 @@ - - - {D6B7E899-542A-4EAB-8F06-E737657B29DE} - CoreUtility - CoreUtility - {DFA822CA-CE06-4ECB-BA60-EB2A256E28F6} Microsoft.CodeAnalysis.ExternalAccess.FSharp @@ -222,18 +217,13 @@ + {27096E7F-C91C-4AC6-B289-6897A701DF21} MonoDevelop.Ide False - - {7525BB88-6142-4A26-93B9-A30C6983390A} - MonoDevelop.Core - - False - @@ -253,7 +243,24 @@ {2357AABD-08C7-4808-A495-8FF2D3CDFDB0} MonoDevelop.Debugger - + + {7525BB88-6142-4A26-93B9-A30C6983390A} + MonoDevelop.Core + + False + + + {D6B7E899-542A-4EAB-8F06-E737657B29DE} + CoreUtility + CoreUtility + + + + + {AF5FEAD5-B50E-4F07-A274-32F23D5C504D} + MonoDevelop.FSharp.Shared + + diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index 0202c90863c..52fc81a4406 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -47,4 +47,16 @@ blockCommentEndTag="*)" codeDomType="FSharp.Compiler.CodeDom.FSharpCleanCodeProvider" /> + + + + + + + + + + + + \ No newline at end of file From 7214cd9909b7b8a726e458732b77ea0f181c2d2a Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 31 Mar 2020 12:43:08 +0100 Subject: [PATCH 063/101] Porting Interactive pad to new editor --- .../VSMac/InteractiveCompletionService.fs | 415 ++++++++++ .../src/FSharp.Editor/VSMac/InteractivePad.fs | 736 ++++++++++++++++++ .../FSharp.Editor/VSMac/InteractiveSession.fs | 176 +++++ 3 files changed, 1327 insertions(+) create mode 100644 vsintegration/src/FSharp.Editor/VSMac/InteractiveCompletionService.fs create mode 100644 vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs create mode 100644 vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveCompletionService.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveCompletionService.fs new file mode 100644 index 00000000000..57927248111 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveCompletionService.fs @@ -0,0 +1,415 @@ +// +// InteractiveCompletionService.fs +// +// Author: +// jasonimison +// +// Copyright (c) Microsoft Corporation. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +namespace Microsoft.VisualStudio.FSharp.Editor + +open System.Composition +open System.Collections.Immutable + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.Completion +open Microsoft.CodeAnalysis.Host.Mef +open Microsoft.CodeAnalysis.ExternalAccess.FSharp +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion +open System.ComponentModel.Composition +open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion +open Microsoft.VisualStudio.Text.Editor +open System.Threading.Tasks + +open System.Collections.Generic; +open Microsoft.CodeAnalysis.Classification +open Microsoft.CodeAnalysis.Text; +open Microsoft.VisualStudio.Text; +open Microsoft.VisualStudio.Text.Adornments; + +open FSharp.Compiler.SourceCodeServices + + +type CompletionType = + | Document of Document + | Interactive + +type internal InteractiveCompletionService + ( + workspace: Workspace, + checkerProvider: FSharpCheckerProvider, + projectInfoManager: FSharpProjectOptionsManager, + assemblyContentProvider: AssemblyContentProvider, + settings: EditorOptions + ) = + inherit CompletionServiceWithProviders(workspace) + + let builtInProviders = + ImmutableArray.Create( + FSharpCompletionProvider(workspace, (*serviceProvider,*) checkerProvider, projectInfoManager, assemblyContentProvider), + FSharpCommonCompletionProvider.Create( + HashDirectiveCompletionProvider(workspace, projectInfoManager, + [ Completion.Create("""\s*#load\s+(@?"*(?"[^"]*"?))""", [".fs"; ".fsx"], useIncludeDirectives = true) + Completion.Create("""\s*#r\s+(@?"*(?"[^"]*"?))""", [".dll"; ".exe"], useIncludeDirectives = true) + Completion.Create("""\s*#I\s+(@?"*(?"[^"]*"?))""", ["\x00"], useIncludeDirectives = false) ]))) + + override this.Language = FSharpConstants.FSharpLanguageName + override this.GetBuiltInProviders() = builtInProviders + override this.GetRules() = + let enterKeyRule = + match settings.IntelliSense.EnterKeySetting with + | NeverNewline -> EnterKeyRule.Never + | NewlineOnCompleteWord -> EnterKeyRule.AfterFullyTypedWord + | AlwaysNewline -> EnterKeyRule.Always + + CompletionRules.Default + .WithDismissIfEmpty(true) + .WithDismissIfLastCharacterDeleted(true) + .WithDefaultEnterKeyRule(enterKeyRule) + +[] +[, FSharpConstants.FSharpContentTypeName)>] +type internal FSharpCompletionSource + (textView: ITextView, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider) = + + + //let settings: EditorOptions = textView.TextBuffer.GetWorkspace().Services.GetService() + + let createParagraphFromLines(lines: List) = + if lines.Count = 1 then + // The paragraph contains only one line, so it doesn't need to be added to a container. Avoiding the + // wrapping container here also avoids a wrapping element in the Cocoa elements used for rendering, + // improving efficiency. + lines.[0] :> obj + else + // The lines of a multi-line paragraph are stacked to produce the full paragraph. + ContainerElement(ContainerElementStyle.Stacked, lines |> Seq.map box) :> obj + + let toClassificationTypeName = function + | TextTags.Keyword -> + ClassificationTypeNames.Keyword + + | TextTags.Class -> + ClassificationTypeNames.ClassName + + | TextTags.Delegate -> + ClassificationTypeNames.DelegateName + + | TextTags.Enum -> + ClassificationTypeNames.EnumName + + | TextTags.Interface -> + ClassificationTypeNames.InterfaceName + + | TextTags.Module -> + ClassificationTypeNames.ModuleName + + | TextTags.Struct -> + ClassificationTypeNames.StructName + + | TextTags.TypeParameter -> + ClassificationTypeNames.TypeParameterName + + | TextTags.Field -> + ClassificationTypeNames.FieldName + + | TextTags.Event -> + ClassificationTypeNames.EventName + + | TextTags.Label -> + ClassificationTypeNames.LabelName + + | TextTags.Local -> + ClassificationTypeNames.LocalName + + | TextTags.Method -> + ClassificationTypeNames.MethodName + + | TextTags.Namespace -> + ClassificationTypeNames.NamespaceName + + | TextTags.Parameter -> + ClassificationTypeNames.ParameterName + + | TextTags.Property -> + ClassificationTypeNames.PropertyName + + | TextTags.ExtensionMethod -> + ClassificationTypeNames.ExtensionMethodName + + | TextTags.EnumMember -> + ClassificationTypeNames.EnumMemberName + + | TextTags.Constant -> + ClassificationTypeNames.ConstantName + + | TextTags.Alias + | TextTags.Assembly + | TextTags.ErrorType + | TextTags.RangeVariable -> + ClassificationTypeNames.Identifier + + | TextTags.NumericLiteral -> + ClassificationTypeNames.NumericLiteral + + | TextTags.StringLiteral -> + ClassificationTypeNames.StringLiteral + + | TextTags.Space + | TextTags.LineBreak -> + ClassificationTypeNames.WhiteSpace + + | TextTags.Operator -> + ClassificationTypeNames.Operator + + | TextTags.Punctuation -> + ClassificationTypeNames.Punctuation + + | TextTags.AnonymousTypeIndicator + | TextTags.Text + | _ -> + ClassificationTypeNames.Text + + + let buildClassifiedTextElements (taggedTexts:ImmutableArray) = + // This method produces a sequence of zero or more paragraphs + let paragraphs = new List() + + // Each paragraph is constructed from one or more lines + let currentParagraph = new List() + + // Each line is constructed from one or more inline elements + let currentRuns = new List() + + for part in taggedTexts do + if part.Tag = TextTags.LineBreak then + if currentRuns.Count > 0 then + // This line break means the end of a line within a paragraph. + currentParagraph.Add(new ClassifiedTextElement(currentRuns)); + currentRuns.Clear(); + else + // This line break means the end of a paragraph. Empty paragraphs are ignored, but could appear + // in the input to this method: + // + // * Empty elements + // * Explicit line breaks at the start of a comment + // * Multiple line breaks between paragraphs + if currentParagraph.Count > 0 then + // The current paragraph is not empty, so add it to the result collection + paragraphs.Add(createParagraphFromLines(currentParagraph)) + currentParagraph.Clear(); + + else + // This is tagged text getting added to the current line we are building. + currentRuns.Add(new ClassifiedTextRun(part.Tag |> toClassificationTypeName, part.Text)) + + if currentRuns.Count > 0 then + // Add the final line to the final paragraph. + currentParagraph.Add(new ClassifiedTextElement(currentRuns)) + + if currentParagraph.Count > 0 then + // Add the final paragraph to the result. + paragraphs.Add(createParagraphFromLines(currentParagraph)) + + paragraphs + /// + /// Called when user interacts with expander buttons, + /// requesting the completion source to provide additional completion items pertinent to the expander button. + /// For best performance, do not provide unless expansion should add new filters. + /// Called on a background thread. + /// + /// Reference to the active + /// Expander which caused this call + /// What initially caused the completion + /// Location where completion will take place, on the view's data buffer: + /// Cancellation token that may interrupt this operation + /// A struct that holds completion items and applicable span + let commitChars = [|' '; '='; ','; '.'; '<'; '>'; '('; ')'; '!'; ':'; '['; ']'; '|'|].ToImmutableArray() + + let projectId = ProjectId.CreateNewId("F# Interactive") + let documentId = DocumentId.CreateNewId(projectId, "F# Interactive") + + interface IAsyncExpandingCompletionSource with + member __.GetExpandedCompletionContextAsync(session, expander, initialTrigger, applicableToSpan, token) = + let ctx = Data.CompletionContext.Empty + Task.FromResult ctx + + + interface IAsyncCompletionSource with + member this.GetCompletionContextAsync(session, trigger, triggerLocation, applicableToSpan, token) = + //let getProjectOptions completionType (sourceText: SourceText) = + //async { + // match! completionType with + // | Interactive -> + // let scriptProjectOptions, _ = checkerProvider.Checker.GetProjectOptionsFromScript("__FSI__.fsx", sourceText.ToFSharpSourceText()) |> Async.RunSynchronously + // "__FSI__.fsx", scriptProjectOptions, VersionStamp.Default + + // | Document document -> + + // let options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, token) |> Async.RunSynchronously + // match options with + // | Some (_parsingOptions, projectOptions) -> + // let version = + // match document.TryGetTextVersion() with + // | true, version -> version + // | _ -> VersionStamp.Create() + + // document.FilePath, projectOptions, version + + // | _ -> failwith "Could not get options" + //} + + async { + System.Diagnostics.Trace.WriteLine("GetCompletionContextAsync") + let document = session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() + + let sourceText = session.TextView.TextSnapshot.AsText() + //let document = + // match document with + // | null -> + // let workspace = new AdhocWorkspace() + // let projectInfo = ProjectInfo.Create(projectId, VersionStamp.Create(), "name", "name.dll", "F#") + // let project = workspace.AddProject(projectInfo) + // project.AddDocument("__FSI__.fsx", sourceText) + // | _ -> document + + let filePath, projectOptions, textVersion = + match document with + | null -> + let scriptProjectOptions, _ = checkerProvider.Checker.GetProjectOptionsFromScript("__FSI__.fsx", sourceText.ToFSharpSourceText()) |> Async.RunSynchronously + "__FSI__.fsx", scriptProjectOptions, VersionStamp.Default + | _ -> + let options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, token) |> Async.RunSynchronously + match options with + | Some (_parsingOptions, projectOptions) -> + let version = + match document.TryGetTextVersion() with + | true, version -> version + | _ -> VersionStamp.Create() + + document.FilePath, projectOptions, version + + | _ -> failwith "Could not get options" + + + //let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, token) + //match options with + //| Some (_parsingOptions, projectOptions) -> + let getAllSymbols(fileCheckResults: FSharpCheckFileResults) = + [] + //if settings.IntelliSense.IncludeSymbolsFromUnopenedNamespacesOrModules + //then assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies(fileCheckResults) + //else [] + + + session.TextView.Properties.["PotentialCommitCharacters"] <- commitChars + let! completions = FSharpCompletionProvider.ProvideCompletionsAsyncAux(this, checkerProvider.Checker, sourceText, triggerLocation.Position, projectOptions, filePath, textVersion.GetHashCode(), getAllSymbols, (*settings.LanguageServicePerformance*) LanguageServicePerformanceOptions.Default, (*settings.IntelliSense*) IntelliSenseOptions.Default) + match completions with + | Some completions' -> + return new Data.CompletionContext(completions'.ToImmutableArray()) + | None -> + return Data.CompletionContext.Empty + //| _ -> + // return Data.CompletionContext.Empty + } |> RoslynHelpers.StartAsyncAsTask token + + /// + /// Returns tooltip associated with provided . + /// The returned object will be rendered by . See its documentation for default supported types. + /// You may export a to provide a renderer for a custom type. + /// Since this method is called on a background thread and on multiple platforms, an instance of UIElement may not be returned. + /// + /// Reference to the active + /// which is a subject of the tooltip + /// Cancellation token that may interrupt this operation + /// An object that will be passed to . See its documentation for supported types. + member __.GetDescriptionAsync(session, item, token) = + async { + let document = session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() + //let! sourceText = document.GetTextAsync() |> Async.AwaitTask + let provider = FSharpCompletionProvider(document.Project.Solution.Workspace, checkerProvider, projectInfoManager, assemblyContentProvider) + let! description = provider.GetDescriptionAsync2(session.TextView, item, token) |> Async.AwaitTask + let elements = description.TaggedParts |> buildClassifiedTextElements + return ContainerElement(ContainerElementStyle.Stacked ||| ContainerElementStyle.VerticalPadding, elements |> Seq.map box) :> obj + //return elements :> obj + } |> RoslynHelpers.StartAsyncAsTask token + + /// + /// Provides the span applicable to the prospective session. + /// Called on UI thread and expected to return very quickly, based on syntactic clues. + /// This method is called as a result of user action, after the Editor makes necessary changes in direct response to user's action. + /// The state of the Editor prior to making the text edit is captured in of . + /// This method is called sequentially on available s until one of them returns + /// with appropriate level of + /// and one returns with + /// If neither of the above conditions are met, no completion session will start. + /// + /// + /// If a language service does not wish to participate in completion, it should try to provide a valid + /// and set to false. + /// This will enable other extensions to provide completion in syntactically appropriate location. + /// + /// What causes the completion, including the character typed and reference to prior to triggering the completion + /// Location on the subject buffer that matches this 's content type + /// Cancellation token that may interrupt this operation + /// Whether this wishes to participate in completion. + member __.InitializeCompletion(trigger, triggerLocation, token) = + System.Diagnostics.Trace.WriteLine("initialize") + use _logBlock = Logger.LogBlock LogEditorFunctionId.Completion_ShouldTrigger + + let document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges() + + let getInfo() = + match document with + | null -> + (documentId, "__FSI__.fsx", []) + | _ -> + let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) + (document.Id, document.FilePath, defines) + + let sourceText = triggerLocation.Snapshot.AsText() + let shouldTrigger = + FSharpCompletionProvider.ShouldTriggerCompletionAux(sourceText, triggerLocation.Position, trigger, getInfo, (*settings.IntelliSense*) IntelliSenseOptions.Default) + + match shouldTrigger with + | false -> + Data.CompletionStartData.DoesNotParticipateInCompletion + | true -> + Data.CompletionStartData( + participation = Data.CompletionParticipation.ProvidesItems, + applicableToSpan = new SnapshotSpan( + triggerLocation.Snapshot, + CompletionUtils.getCompletionItemSpan sourceText triggerLocation.Position)) + +[)>] +[)>] +[] +[] +type internal CompletionSourceProvider + [] + ( + checkerProvider: FSharpCheckerProvider, + projectInfoManager: FSharpProjectOptionsManager, + assemblyContentProvider: AssemblyContentProvider + ) = + + interface IAsyncCompletionSourceProvider with + member __.GetOrCreate(textView) = + System.Diagnostics.Trace.WriteLine("Completion .ctor") + new FSharpCompletionSource(textView, checkerProvider, projectInfoManager, assemblyContentProvider) :> _ + + interface IAsyncCompletionCommitManagerProvider with + member __.GetOrCreate(_textView) = + System.Diagnostics.Trace.WriteLine("GetOrCreate FSharpAsyncCompletionCommitManager") + FSharpAsyncCompletionCommitManager() :> _ diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs new file mode 100644 index 00000000000..0fb48df4947 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -0,0 +1,736 @@ + +// +// InteractivePad.fs +// +// Author: +// jasonimison +// +// Copyright (c) 2020 Microsoft +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +namespace FSharp.Editor + +open System +open System.IO +open System.Threading.Tasks +open System.Collections.Generic + +open Gdk +open MonoDevelop.Components +open MonoDevelop.Components.Docking +open MonoDevelop.Components.Commands +open MonoDevelop.Core +open MonoDevelop.Core.Execution +open MonoDevelop.FSharp +open MonoDevelop.Ide +open MonoDevelop.Ide.CodeCompletion +open MonoDevelop.Ide.Editor +open MonoDevelop.Ide.Editor.Extension +open MonoDevelop.Ide.Gui.Content +open MonoDevelop.Ide.TypeSystem +open MonoDevelop.Projects +open Microsoft.VisualStudio.Text.Editor +open MonoDevelop.Ide.Composition +open Microsoft.VisualStudio.Text +open Gtk +open Microsoft.VisualStudio.Text.Classification +open CoreGraphics + +[] +module ColorHelpers = + let strToColor s = + let c = ref (Color()) + match Color.Parse (s, c) with + | true -> !c + | false -> Color() // black is as good a guess as any here + + let colorToStr (c:Color) = + sprintf "#%04X%04X%04X" c.Red c.Green c.Blue + + let cairoToGdk (c:Cairo.Color) = GtkUtil.ToGdkColor(c) + +type FSharpCommands = + | ShowFSharpInteractive = 0 + | SendSelection = 1 + | SendLine = 2 + | SendFile = 3 + +type KillIntent = + | Restart + | Kill + | NoIntent // Unexpected kill, or from #q/#quit, so we prompt + +//type ImageRendererMarker(line, image:Xwt.Drawing.Image) = +// inherit TextLineMarker() +// static let tag = obj() +// override x.Draw(editor, cr, metrics) = +// cr.DrawImage(editor, image, 30.0, metrics.LineYRenderStartPosition) + +// interface ITextLineMarker with +// member x.Line with get() = line +// member x.IsVisible with get() = true and set(_value) = () +// member x.Tag with get() = tag and set(_value) = () + +// interface IExtendingTextLineMarker with +// member x.GetLineHeight editor = editor.LineHeight + image.Height +// member x.Draw(_editor, _g, _lineNr, _lineArea) = () +// member x.IsSpaceAbove with get() = false + +//type FsiDocumentContext() = +// inherit DocumentContext() +// static let name = "__FSI__.fs" +// let pd = new FSharpParsedDocument(name, None, None) :> ParsedDocument +// let project = Services.ProjectService.CreateDotNetProject ("F#") + +// let mutable completionWidget:ICompletionWidget = null +// let mutable editor:TextEditor = null + +// let contextChanged = DelegateEvent<_>() +// let mutable workingFolder: string option = None +// do +// project.FileName <- FilePath name + +// override x.ParsedDocument = pd +// override x.AttachToProject(_) = () +// override x.ReparseDocument() = () +// override x.GetOptionSet() = IdeApp.TypeSystemService.Workspace.Options +// override x.Project = project :> Project +// override x.Name = name +// override x.AnalysisDocument with get() = null +// override x.UpdateParseDocument() = Task.FromResult pd +// static member DocumentName = name +// member x.CompletionWidget +// with set (value) = +// completionWidget <- value +// completionWidget.CompletionContextChanged.Add +// (fun _args -> let completion = editor.GetContent() +// ParameterInformationWindowManager.HideWindow(completion, value)) +// member x.Editor with set (value) = editor <- value +// member x.WorkingFolder +// with get() = workingFolder +// and set(folder) = workingFolder <- folder +// interface ICompletionWidget with +// member x.CaretOffset +// with get() = completionWidget.CaretOffset +// and set(offset) = completionWidget.CaretOffset <- offset +// member x.TextLength = editor.Length +// member x.SelectedLength = completionWidget.SelectedLength +// member x.GetText(startOffset, endOffset) = +// completionWidget.GetText(startOffset, endOffset) +// member x.GetChar offset = editor.GetCharAt offset +// member x.Replace(offset, count, text) = +// completionWidget.Replace(offset, count, text) +// member x.GtkStyle = completionWidget.GtkStyle + +// member x.ZoomLevel = completionWidget.ZoomLevel +// member x.CreateCodeCompletionContext triggerOffset = +// completionWidget.CreateCodeCompletionContext triggerOffset +// member x.CurrentCodeCompletionContext +// with get() = completionWidget.CurrentCodeCompletionContext + +// member x.GetCompletionText ctx = completionWidget.GetCompletionText ctx + +// member x.SetCompletionText (ctx, partialWord, completeWord) = +// completionWidget.SetCompletionText (ctx, partialWord, completeWord) +// member x.SetCompletionText (ctx, partialWord, completeWord, completeWordOffset) = +// completionWidget.SetCompletionText (ctx, partialWord, completeWord, completeWordOffset) +// [] +// member x.CompletionContextChanged = contextChanged.Publish + +//type FsiPrompt(icon: Xwt.Drawing.Image) = +// inherit MarginMarker() + +// override x.CanDrawForeground margin = +// margin :? IconMargin + +// override x.DrawForeground (editor, cairoContext, metrics) = +// let size = metrics.Margin.Width +// let borderLineWidth = cairoContext.LineWidth + +// let x = Math.Floor (metrics.Margin.XOffset - borderLineWidth / 2.0) +// let y = Math.Floor (metrics.Y + (metrics.Height - size) / 2.0) + +// let deltaX = size / 2.0 - icon.Width / 2.0 + 0.5 +// let deltaY = size / 2.0 - icon.Height / 2.0 + 0.5 +// cairoContext.DrawImage (editor, icon, Math.Round (x + deltaX), Math.Round (y + deltaY)); + +type ShellHistory() = + let history = ResizeArray() + let mutable nextUp = 0 + let mutable nextDown = 0 + + member x.Push command = + history.Add command + nextUp <- history.Count - 1 + nextDown <- history.Count - 1 + + member x.Up() = + match nextUp with + | -1 -> None + | index -> + nextDown <- nextUp + nextUp <- nextUp - 1 + Some history.[index] + + member x.Down() = + if nextDown = history.Count then + None + else + nextUp <- nextDown + nextDown <- nextDown + 1 + if nextDown = history.Count then + None + else + Some history.[nextDown] + +module InteractiveContentTypeName = + [] + let ContentTypeName = "F#" + +type InteractiveContentTypeDefinition() = + [] + [] + [] + member val InteractiveContentTypeDefinition: Microsoft.VisualStudio.Utilities.ContentTypeDefinition = null with get, set + +[] +[] +[] +type InteractivePadController() as this = + let mutable view = null + let mutable textView = null + do + let contentTypeRegistry = CompositionManager.Instance.GetExportedValue() + let textBufferFactory = CompositionManager.Instance.GetExportedValue() + let factory = CompositionManager.Instance.GetExportedValue() + let contentType = contentTypeRegistry.GetContentType(InteractiveContentTypeName.ContentTypeName) + let editorFormatMapService = CompositionManager.Instance.GetExportedValue() + //let appearanceCategory = Guid.NewGuid().ToString() + //let editorFormat = editorFormatMapService.GetEditorFormatMap(appearanceCategory) + //let resourceDictionary = editorFormat.GetProperties("Plain Text") + //resourceDictionary.[ClassificationFormatDefinition.TypefaceId] <- TextField.Font + //resourceDictionary.[ClassificationFormatDefinition.FontRenderingSizeId] <- 20 + //resourceDictionary.[ClassificationFormatDefinition.BackgroundBrushId] <- System.Windows.Media.Brushes.Black + //resourceDictionary.[ClassificationFormatDefinition.ForegroundColorId] <- System.Windows.Media.Brushes.Black + //editorFormat.SetProperties("Plain Text", resourceDictionary) + + let roles = factory.CreateTextViewRoleSet(PredefinedTextViewRoles.Analyzable, PredefinedTextViewRoles.Editable, PredefinedTextViewRoles.Interactive) + let textBuffer = textBufferFactory.CreateTextBuffer("", contentType) + + textView <- factory.CreateTextView(textBuffer, roles) + //textView.Background <- CGColor.CreateSrgb(nfloat 0.0, nfloat 0.0, nfloat 0.0, nfloat 0.0) + textView.Options.SetOptionValue(DefaultTextViewOptions.UseVisibleWhitespaceId, false) + //textView.Options.SetOptionValue(DefaultCocoaViewOptions.AppearanceCategory, appearanceCategory) + textView.Options.SetOptionValue(DefaultTextViewHostOptions.ChangeTrackingId, false) + textView.Options.SetOptionValue(DefaultTextViewHostOptions.LineNumberMarginId, false) + textView.Options.SetOptionValue(DefaultTextViewHostOptions.OutliningMarginId, false) + textView.Options.SetOptionValue(DefaultTextViewHostOptions.GlyphMarginId, true) + textView.VisualElement.TranslatesAutoresizingMaskIntoConstraints <- false + textView.Properties.[typeof] <- this + let host = factory.CreateTextViewHost(textView, true) + view <- host.HostControl + + member this.View = view + + member this.FsiOutput text = + let buffer = textView.TextBuffer + use edit = buffer.CreateEdit() + let position = buffer.CurrentSnapshot.Length + + if edit.Insert(position, text) then + edit.Apply() |> ignore + +type FSharpInteractivePad() as this = + inherit MonoDevelop.Ide.Gui.PadContent() + + //let ctx = editor.DocumentContext :?> FsiDocumentContext + //do + // let options = new CustomEditorOptions (editor.Options) + // editor.MimeType <- "text/x-fsharp" + // editor.ContextMenuPath <- "/MonoDevelop/SourceEditor2/ContextMenu/Fsi" + // options.ShowLineNumberMargin <- false + // options.TabsToSpaces <- true + // options.ShowWhitespaces <- ShowWhitespaces.Never + // ctx.CompletionWidget <- editor.GetContent() + // ctx.Editor <- editor + // editor.Options <- options + + let mutable killIntent = NoIntent + let mutable promptReceived = false + let mutable activeDoc : IDisposable option = None + let mutable lastLineOutput = None + + let promptIcon = ImageService.GetIcon("md-breadcrumb-next") + let newLineIcon = ImageService.GetIcon("md-template") + + let getActiveDocumentFileName () = + if IdeApp.Workbench.ActiveDocument <> null && FileService.isInsideFSharpFile() then + let docFileName = IdeApp.Workbench.ActiveDocument.FileName.ToString() + if docFileName <> null then + let directoryName = Path.GetDirectoryName docFileName + //ctx.WorkingFolder <- Some directoryName + Some docFileName + else None + else None + + let nonBreakingSpace = "\u00A0" // used to disable editor syntax highlighting for output + + //let addMarker image = + // let data = editor.GetContent().GetTextEditorData() + // let textDocument = data.Document + + // let line = data.GetLineByOffset editor.Length + // let prompt = FsiPrompt image + + // textDocument.AddMarker(line, prompt) + + // textDocument.CommitUpdateAll() + + let setPrompt() = + () + //editor.InsertText(editor.Length, "\n") + //editor.ScrollTo editor.Length + //addMarker promptIcon + + //let renderImage image = + // let data = editor.GetContent().GetTextEditorData() + // let textDocument = data.Document + // let line = editor.GetLine editor.CaretLine + // let imageMarker = ImageRendererMarker(line, image) + // textDocument.AddMarker(editor.CaretLine, imageMarker) + // textDocument.CommitUpdateAll() + // editor.InsertAtCaret "\n" + + let input = new ResizeArray<_>() + + let setupSession() = + try + let pathToExe = + Path.Combine(Reflection.Assembly.GetExecutingAssembly().Location |> Path.GetDirectoryName, "MonoDevelop.FSharpInteractive.Service.exe") + |> ProcessArgumentBuilder.Quote + let controller = new InteractivePadController(); + this.Host <- new GtkNSViewHost(controller.View) + this.Host.ShowAll() + + let ses = InteractiveSession(pathToExe) + input.Clear() + promptReceived <- false + let textReceived = ses.TextReceived.Subscribe(fun t -> Runtime.RunInMainThread(fun () -> controller.FsiOutput t) |> ignore) + //let imageReceived = ses.ImageReceived.Subscribe(fun image -> Runtime.RunInMainThread(fun () -> renderImage image) |> Async.AwaitTask |> Async.RunSynchronously) + let promptReady = ses.PromptReady.Subscribe(fun () -> Runtime.RunInMainThread(fun () -> promptReceived <- true; setPrompt() ) |> ignore) + + ses.Exited.Add(fun _ -> + textReceived.Dispose() + promptReady.Dispose() + //imageReceived.Dispose() + if killIntent = NoIntent then + Runtime.RunInMainThread(fun () -> + LoggingService.LogDebug ("Interactive: process stopped") + (*this.FsiOutput "\nSession termination detected. Press Enter to restart." *))|> ignore + elif killIntent = Restart then + Runtime.RunInMainThread (fun () -> ()(*editor.Text <- ""*)) |> ignore + killIntent <- NoIntent) + + ses.StartReceiving() + //editor.GrabFocus() + Some(ses) + with _exn -> None + + let mutable session = None + + let setCaretLine (s: string) = () + //let line = editor.GetLineByOffset editor.CaretOffset + //editor.ReplaceText(line.Offset, line.EndOffset - line.Offset, s) + + let resetFsi intent = + if promptReceived then + killIntent <- intent + //session |> Option.iter (fun (ses: InteractiveSession) -> ses.Kill()) + //if intent = Restart then session <- setupSession() + + let history = ShellHistory() + //new() = + // let ctx = FsiDocumentContext() + // let doc = TextEditorFactory.CreateNewDocument() + // do + // doc.FileName <- FilePath ctx.Name + + // let editor = TextEditorFactory.CreateNewEditor(ctx, doc, TextEditorType.Default) + // new FSharpInteractivePad(editor) + + //member x.FsiOutput t : unit = + // if editor.CaretColumn <> 1 then + // editor.InsertAtCaret ("\n") + // editor.InsertAtCaret (nonBreakingSpace + t) + // editor.CaretOffset <- editor.Text.Length + // editor.ScrollTo editor.CaretLocation + // lastLineOutput <- Some editor.CaretLine + + //member x.Text = + // editor.Text + + //member x.SetPrompt() = + // editor.InsertText(editor.Length, "\n") + // editor.ScrollTo editor.Length + // addMarker promptIcon + + //member x.AddMorePrompt() = + // addMarker newLineIcon + + member x.Session = session + + member x.Shutdown() = + do LoggingService.LogDebug ("Interactive: Shutdown()!") + resetFsi Kill + + //member x.SendCommandAndStore command = + // let fileName = getActiveDocumentFileName() + // input.Add command + // session + // |> Option.iter(fun ses -> + // history.Push command + // ses.SendInput (command + "\n") fileName) + + //member x.SendCommand command = + // let fileName = getActiveDocumentFileName() + + // input.Add command + // session + // |> Option.iter(fun ses -> + // ses.SendInput (command + ";;") fileName) + + //member x.RequestCompletions lineStr column = + // session + // |> Option.iter(fun ses -> + // ses.SendCompletionRequest lineStr (column + 1)) + + //member x.RequestTooltip symbol = + // session + // |> Option.iter(fun ses -> ses.SendTooltipRequest symbol) + + //member x.RequestParameterHint lineStr column = + // session + // |> Option.iter(fun ses -> + // ses.SendParameterHintRequest lineStr (column + 1)) + + member x.ProcessCommandHistoryUp () = + history.Up() + |> Option.iter setCaretLine + + member x.ProcessCommandHistoryDown () = + history.Down() + |> function Some c -> setCaretLine c | None -> setCaretLine "" + + override x.Dispose() = + LoggingService.LogDebug ("Interactive: disposing pad...") + activeDoc |> Option.iter (fun ad -> ad.Dispose()) + x.Shutdown() + //editor.Dispose() + + override x.Control = Control.op_Implicit x.Host + + static member Pad = + try let pad = IdeApp.Workbench.GetPad() + + if pad <> null then Some(pad) + else + //*attempt* to add the pad manually this seems to fail sporadically on updates and reinstalls, returning null + let pad = IdeApp.Workbench.AddPad(new FSharpInteractivePad(), + "FSharp.MonoDevelop.FSharpInteractivePad", + "F# Interactive", + "Center Bottom", + IconId("md-fs-project")) + if pad <> null then Some(pad) + else None + with exn -> None + + static member BringToFront(grabfocus) = + FSharpInteractivePad.Pad |> Option.iter (fun pad -> pad.BringToFront(grabfocus)) + + static member Fsi = + FSharpInteractivePad.Pad |> Option.bind (fun pad -> Some(pad.Content :?> FSharpInteractivePad)) + + member x.LastOutputLine + with get() = lastLineOutput + and set value = lastLineOutput <- value + + member x.SendSelection() = + if x.IsSelectionNonEmpty then + let textView = IdeApp.Workbench.ActiveDocument.GetContent() + () + //for span in textView.Selection.VirtualSelectedSpans do + // x.SendCommand (span.GetText()) + else + //if nothing is selected send the whole line + x.SendLine() + + member x.SendLine() = + if isNull IdeApp.Workbench.ActiveDocument then () + else + let view = IdeApp.Workbench.ActiveDocument.GetContent(); + let line = view.Caret.Position.BufferPosition.GetContainingLine(); + let text = line.GetText() + //x.SendCommand text + () + + member x.SendFile() = + let text = IdeApp.Workbench.ActiveDocument.TextBuffer.CurrentSnapshot.GetText() + //x.SendCommand text + () + + member x.IsSelectionNonEmpty = + if isNull IdeApp.Workbench.ActiveDocument || + isNull IdeApp.Workbench.ActiveDocument.FileName.FileName then false + else + let textView = IdeApp.Workbench.ActiveDocument.GetContent() + not(textView.Selection.IsEmpty) + + member x.LoadReferences(project:FSharpProject) = + LoggingService.LogDebug ("FSI: #LoadReferences") + async { + let! orderedReferences = project.GetOrderedReferences (CompilerArguments.getConfig()) + orderedReferences |> List.iter (fun a -> (*x.SendCommand (sprintf @"#r ""%s""" a.Path)) *) ()) + } |> Async.StartImmediate + + member val Host:GtkNSViewHost = null with get, set + member val Controller:InteractivePadController option = None with get, set + + override x.Initialize(container:MonoDevelop.Ide.Gui.IPadWindow) = + //this.Controller <- Some controller + //controller.ConsoleInput += OnViewConsoleInput; + //controller.Editable <- true; + + LoggingService.LogDebug ("InteractivePad: created!") + //editor.MimeType <- "text/x-fsharp" + //ctx.CompletionWidget <- editor.GetContent() + //ctx.Editor <- editor + let toolbar = container.GetToolbar(DockPositionType.Right) + + let addButton(icon, action, tooltip) = + let button = new DockToolButton(icon) + button.Clicked.Add(action) + button.TooltipText <- tooltip + toolbar.Add(button) + + addButton ("gtk-save", (fun _ -> x.Save()), GettextCatalog.GetString ("Save as script")) + addButton ("gtk-open", (fun _ -> x.OpenScript()), GettextCatalog.GetString ("Open")) + //addButton ("gtk-clear", (fun _ -> editor.Text <- ""), GettextCatalog.GetString ("Clear")) + addButton ("gtk-refresh", (fun _ -> x.RestartFsi()), GettextCatalog.GetString ("Reset")) + toolbar.ShowAll() + session <- setupSession() + //editor.RunWhenRealized(fun () -> session <- setupSession()) + + member x.RestartFsi() = resetFsi Restart + + //member x.ClearFsi() = editor.Text <- "" + + member x.Save() = + let dlg = new MonoDevelop.Ide.Gui.Dialogs.OpenFileDialog(GettextCatalog.GetString ("Save as .fsx"), MonoDevelop.Components.FileChooserAction.Save) + + dlg.DefaultFilter <- dlg.AddFilter (GettextCatalog.GetString ("F# script files"), "*.fsx") + if dlg.Run () then + let file = + if dlg.SelectedFile.Extension = ".fsx" then + dlg.SelectedFile + else + dlg.SelectedFile.ChangeExtension(".fsx") + + let lines = []// input |> Seq.map (fun line -> line.TrimEnd(';')) + let fileContent = String.concat "\n" lines + File.WriteAllText(file.FullPath.ToString(), fileContent) + + member x.OpenScript() = + let dlg = MonoDevelop.Ide.Gui.Dialogs.OpenFileDialog(GettextCatalog.GetString ("Open script"), MonoDevelop.Components.FileChooserAction.Open) + dlg.AddFilter (GettextCatalog.GetString ("F# script files"), [|".fs"; "*.fsi"; "*.fsx"; "*.fsscript"; "*.ml"; "*.mli" |]) |> ignore + if dlg.Run () then + let file = dlg.SelectedFile + //x.SendCommand ("#load @\"" + file.FullPath.ToString() + "\"") + () + +/// handles keypresses for F# Interactive +//type FSharpFsiEditorCompletion() = +// inherit TextEditorExtension() +// override x.IsValidInContext(context) = +// context :? FsiDocumentContext + +// override x.KeyPress (descriptor:KeyDescriptor) = +// match FSharpInteractivePad.Fsi with +// | Some fsi -> +// let getLineText (editor:TextEditor) (line:IDocumentLine) = +// if line.Length > 0 then +// editor.GetLineText line +// else +// "" + +// let getInputLines (editor:TextEditor) = +// let lineNumbers = +// match fsi.LastOutputLine with +// | Some lineNumber -> +// [ lineNumber+1 .. editor.CaretLine ] +// | None -> [ editor.CaretLine ] +// lineNumbers +// |> List.map editor.GetLine +// |> List.map (getLineText editor) + +// let result = +// match descriptor.SpecialKey with +// | SpecialKey.Return -> +// if x.Editor.CaretLine = x.Editor.LineCount then +// let lines = getInputLines x.Editor +// lines +// |> List.iter(fun (lineStr) -> +// fsi.SendCommandAndStore lineStr) + +// let line = x.Editor.GetLine x.Editor.CaretLine +// let lineStr = getLineText x.Editor line +// x.Editor.CaretOffset <- line.EndOffset +// x.Editor.InsertAtCaret "\n" + +// if not (lineStr.TrimEnd().EndsWith(";;")) then +// fsi.AddMorePrompt() +// fsi.LastOutputLine <- Some line.LineNumber +// false +// | SpecialKey.Up -> +// if x.Editor.CaretLine = x.Editor.LineCount then +// fsi.ProcessCommandHistoryUp() +// false +// else +// base.KeyPress (descriptor) +// | SpecialKey.Down -> +// if x.Editor.CaretLine = x.Editor.LineCount then +// fsi.ProcessCommandHistoryDown() +// false +// else +// base.KeyPress (descriptor) +// | SpecialKey.Left -> +// if (x.Editor.CaretLine <> x.Editor.LineCount) || x.Editor.CaretColumn > 1 then +// base.KeyPress (descriptor) +// else +// false +// | SpecialKey.BackSpace -> +// if x.Editor.CaretLine = x.Editor.LineCount && x.Editor.CaretColumn > 1 then +// base.KeyPress (descriptor) +// else +// false +// | _ -> +// if x.Editor.CaretLine <> x.Editor.LineCount then +// x.Editor.CaretOffset <- x.Editor.Length +// base.KeyPress (descriptor) + +// result +// | _ -> base.KeyPress (descriptor) + +// member x.clipboardHandler = x.Editor.GetContent() + +// [] +// member x.Cut() = x.clipboardHandler.Cut() + +// [] +// member x.CanCut(ci:CommandInfo) = +// ci.Enabled <- x.clipboardHandler.EnableCut + +// [] +// member x.Copy() = x.clipboardHandler.Copy() + +// [] +// member x.CanCopy(ci:CommandInfo) = +// ci.Enabled <- x.clipboardHandler.EnableCopy + +// [] +// member x.Paste() = x.clipboardHandler.Paste() + +// [] +// member x.CanPaste(ci:CommandInfo) = +// ci.Enabled <- x.clipboardHandler.EnablePaste + +// [] +// member x.ZoomIn() = x.Editor.GetContent().ZoomIn() + +// [] +// member x.ZoomOut() = x.Editor.GetContent().ZoomOut() + +// [] +// member x.ZoomReset() = x.Editor.GetContent().ZoomReset() + +type InteractiveCommand(command) = + inherit CommandHandler() + + override x.Run() = + FSharpInteractivePad.Fsi + |> Option.iter (fun fsi -> command fsi + FSharpInteractivePad.BringToFront(false)) + +type FSharpFileInteractiveCommand(command) = + inherit InteractiveCommand(command) + + override x.Update(info:CommandInfo) = + info.Enabled <- true + info.Visible <- FileService.isInsideFSharpFile() + +type ShowFSharpInteractive() = + inherit InteractiveCommand(ignore) + override x.Update(info:CommandInfo) = + info.Enabled <- true + info.Visible <- true + +type SendSelection() = + inherit FSharpFileInteractiveCommand(fun fsi -> fsi.SendSelection()) + +type SendLine() = + inherit FSharpFileInteractiveCommand(fun fsi -> fsi.SendLine()) + +type SendFile() = + inherit FSharpFileInteractiveCommand(fun fsi -> fsi.SendFile()) + +type SendReferences() = + inherit CommandHandler() + override x.Run() = + async { + let project = IdeApp.Workbench.ActiveDocument.Owner :?> FSharpProject + FSharpInteractivePad.Fsi + |> Option.iter (fun fsi -> fsi.LoadReferences(project) + FSharpInteractivePad.BringToFront(false)) + } |> Async.StartImmediate + +type RestartFsi() = + inherit InteractiveCommand(fun fsi -> fsi.RestartFsi()) + +//type ClearFsi() = +// inherit InteractiveCommand(fun fsi -> fsi.ClearFsi()) + +//open System.ComponentModel.Composition +//open Microsoft.VisualStudio.Text.Editor +//open MonoDevelop.TextEditor +////open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +////open Microsoft.VisualStudio.FSharp.Editor +//open Microsoft.VisualStudio.Threading + +//[)>] +//[] +//[] +//[] +//type internal FSharpPathedDocumentExtensionProvider +// [] +// ( +// //fsharpCheckerProvider: FSharpCheckerProvider, +// //optionsManager: FSharpProjectOptionsManagerk, +// joinableTaskContext: JoinableTaskContext +// ) as x = +// inherit EditorContentInstanceProvider() + +// override x.CreateInstance(view) = new FSharpPathedDocumentExtension(optionsManager, fsharpCheckerProvider.Checker, view, joinableTaskContext) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs new file mode 100644 index 00000000000..ed039bf50d2 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs @@ -0,0 +1,176 @@ +namespace MonoDevelop.FSharp + +open System +open System.IO +open System.Diagnostics +open MonoDevelop.Core +open Newtonsoft.Json +open Microsoft.VisualStudio.FSharp.Editor.Extensions + +type CompletionData = { + displayText: string + completionText: string + category: string + icon: string + overloads: CompletionData array + description: string +} + +type InteractiveSession(pathToExe) = + let (|Completion|_|) (command: string) = + if command.StartsWith("completion ") then + let payload = command.[11..] + Some (JsonConvert.DeserializeObject payload) + else + None + + let (|Tooltip|_|) (command: string) = + if command.StartsWith("tooltip ") then + let payload = command.[8..] + Some (JsonConvert.DeserializeObject payload) + else + None + + let (|ParameterHints|_|) (command: string) = + if command.StartsWith("parameter-hints ") then + let payload = command.[16..] + Some (JsonConvert.DeserializeObject payload) + else + None + + let (|Image|_|) (command: string) = + if command.StartsWith("image ") then + let base64image = command.[6..command.Length - 1] + let bytes = Convert.FromBase64String base64image + use ms = new MemoryStream(bytes) + Some (Xwt.Drawing.Image.FromStream ms) + else + None + + let (|ServerPrompt|_|) (command:string) = + if command = "SERVER-PROMPT>" then + Some () + else + None + + let mutable waitingForResponse = false + + let fsiProcess = + let processPid = sprintf " %d" (Process.GetCurrentProcess().Id) + + let processName = + if Environment.runningOnMono then Environment.getMonoPath() else pathToExe + + let arguments = + if Environment.runningOnMono then pathToExe + processPid else processPid + + let startInfo = + new ProcessStartInfo + (FileName = processName, UseShellExecute = false, Arguments = arguments, + RedirectStandardError = true, CreateNoWindow = true, RedirectStandardOutput = true, + RedirectStandardInput = true, StandardErrorEncoding = Text.Encoding.UTF8, StandardOutputEncoding = Text.Encoding.UTF8) + + try + Process.Start(startInfo) + with e -> + LoggingService.LogDebug (sprintf "Interactive: Error %s" (e.ToString())) + reraise() + + let textReceived = Event<_>() + let promptReady = Event<_>() + + let sendCommand(str:string) = + waitingForResponse <- true + LoggingService.LogDebug (sprintf "Interactive: sending %s" str) + let stream = fsiProcess.StandardInput.BaseStream + let bytes = Text.Encoding.UTF8.GetBytes(str + "\n") + stream.Write(bytes,0,bytes.Length) + stream.Flush() + + let completionsReceivedEvent = new Event() + let imageReceivedEvent = new Event() + let tooltipReceivedEvent = new Event() + let parameterHintReceivedEvent = new Event() + do + fsiProcess.OutputDataReceived + |> Event.filter (fun de -> de.Data <> null) + |> Event.add (fun de -> + LoggingService.logDebug "Interactive: received %s" de.Data + match de.Data with + | Image image -> imageReceivedEvent.Trigger image + | ServerPrompt -> promptReady.Trigger() + | data -> + if data.Trim() <> "" then + if waitingForResponse then waitingForResponse <- false + textReceived.Trigger(data + "\n")) + + fsiProcess.ErrorDataReceived.Subscribe(fun de -> + if not (String.IsNullOrEmpty de.Data) then + try + match de.Data with + | Completion completions -> + completionsReceivedEvent.Trigger completions + | Tooltip tooltip -> + tooltipReceivedEvent.Trigger tooltip + | ParameterHints hints -> + parameterHintReceivedEvent.Trigger hints + | _ -> LoggingService.logDebug "[fsharpi] don't know how to process command %s" de.Data + + with + | :? JsonException as e -> + LoggingService.logError "[fsharpi] - error deserializing error stream - %s\\n %s" e.Message de.Data + ) |> ignore + + fsiProcess.EnableRaisingEvents <- true + + member x.Interrupt() = + LoggingService.logDebug "Interactive: Break!" + + member x.CompletionsReceived = completionsReceivedEvent.Publish + member x.TooltipReceived = tooltipReceivedEvent.Publish + member x.ParameterHintReceived = parameterHintReceivedEvent.Publish + member x.ImageReceived = imageReceivedEvent.Publish + member x.StartReceiving() = + fsiProcess.BeginOutputReadLine() + fsiProcess.BeginErrorReadLine() + + member x.TextReceived = textReceived.Publish + member x.PromptReady = promptReady.Publish + + member x.HasExited() = fsiProcess.HasExited + + member x.Kill() = + if not fsiProcess.HasExited then + x.SendInput "#q;;" None + for i in 0 .. 10 do + if not fsiProcess.HasExited then + LoggingService.logDebug "Interactive: waiting for process exit after #q... %d" (i*200) + fsiProcess.WaitForExit(200) |> ignore + + if not fsiProcess.HasExited then + fsiProcess.Kill() + for i in 0 .. 10 do + if not fsiProcess.HasExited then + LoggingService.logDebug "Interactive: waiting for process exit after kill... %d" (i*200) + fsiProcess.WaitForExit(200) |> ignore + + member x.KillNow() = fsiProcess.Kill() + + member x.SendInput input documentName = + documentName + |> Option.iter(fun fileName -> + sendCommand (sprintf "input # 0 @\"%s\"" fileName)) + + for line in String.getLines input do + sendCommand ("input " + line) + + member x.SendCompletionRequest input column = + sendCommand (sprintf "completion %d %s" column input) + + member x.SendParameterHintRequest input column = + sendCommand (sprintf "parameter-hints %d %s" column input) + + member x.SendTooltipRequest input = + sendCommand (sprintf "tooltip %s" input) + + member x.Exited = fsiProcess.Exited From 8aec525b4aecd69fea6689671a3a3c1e4ed198be Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 2 Apr 2020 15:57:14 +0100 Subject: [PATCH 064/101] Add prompt --- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 166 +++++++++++++++--- 1 file changed, 143 insertions(+), 23 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index 0fb48df4947..8fd897b33a8 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -29,6 +29,7 @@ open System open System.IO open System.Threading.Tasks open System.Collections.Generic +open System.Collections.Immutable open Gdk open MonoDevelop.Components @@ -50,6 +51,10 @@ open Microsoft.VisualStudio.Text open Gtk open Microsoft.VisualStudio.Text.Classification open CoreGraphics +open Microsoft.VisualStudio.Core.Imaging +open Microsoft.VisualStudio.Text.Tagging +open System.ComponentModel.Composition +open Microsoft.VisualStudio.Imaging [] module ColorHelpers = @@ -200,7 +205,7 @@ type ShellHistory() = module InteractiveContentTypeName = [] - let ContentTypeName = "F#" + let ContentTypeName = "F# Interactive" type InteractiveContentTypeDefinition() = [] @@ -208,32 +213,116 @@ type InteractiveContentTypeDefinition() = [] member val InteractiveContentTypeDefinition: Microsoft.VisualStudio.Utilities.ContentTypeDefinition = null with get, set +type InteractivePromptGlyphTag() = interface IGlyphTag + +type InteractiveGlyphFactory(imageId:ImageId, imageService:IImageService) = + let mutable imageCache: AppKit.NSImage option = None + + interface IGlyphFactory with + member x.GenerateGlyph(line, tag) = + match tag with + | :? InteractivePromptGlyphTag -> + if imageCache.IsNone then + imageCache <- Some(imageService.GetImage (imageId) :?> AppKit.NSImage) + let imageView = AppKit.NSImageView.FromImage imageCache.Value + imageView.SetFrameSize (imageView.FittingSize) + Some (imageView :> obj) + | _ -> None + |> Option.toObj + +[)>] +[] +[] +[)>] +//[] +type InteractiveGlyphFactoryProvider() as this = + [] + member val ImageService:IImageService = null with get, set + + interface IGlyphFactoryProvider with + member x.GetGlyphFactory(view, margin) = + let imageId = ImageId(Guid("{3404e281-57a6-4f3a-972b-185a683e0753}"), 1) + upcast InteractiveGlyphFactory(imageId, x.ImageService) + + +type InteractivePromptGlyphTagger(textView: ITextView) as this = + let tagsChanged = Event<_,_>() + + let promptSpans = HashSet<_>() + let promptsChanged = Event<_>() + + do + // glyphManager.PromptsChanged.Add(fun (args) -> + // tagsChanged.Trigger(this, args))// (this :> ITagger).Ta + textView.Properties.[typeof] <- this + + //member x.Controller = textView.Properties.[typeof] :?> InteractivePadController + + member x.AddPrompt(pos:int) = + if promptSpans.Add(pos) then + tagsChanged.Trigger(this, SnapshotSpanEventArgs(SnapshotSpan(textView.TextSnapshot, pos, 1))) + + interface ITagger with + [] + member this.TagsChanged = tagsChanged.Publish + + /// + /// Occurs when tags are added to or removed from the provider. + /// + //event EventHandler TagsChanged; + //member this.add_TagsChanged(handler) = tagsChanged.Publish + + //member this.remove_TagsChanged(handler) = ()// tagsChanged.Publish.RemoveHandler(handler) + //public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + member x.GetTags(spans) = + seq { + for span in spans do + if promptSpans.Contains(span.Start.Position) then + yield TagSpan(span, InteractivePromptGlyphTag()) + } + +//type InteractiveGlyphManager(textView:ITextView) = +// let promptSpans = HashSet<_>() +// let promptsChanged = new Event<_>() + +// member x.PromptsChanged = promptsChanged.Publish + +// member x.PromptSpans = promptSpans + +// member x.AddPrompt(pos:int) = +// if promptSpans.Add(pos) then +// promptsChanged.Trigger(new SnapshotSpanEventArgs(new SnapshotSpan(textView.TextSnapshot, pos, 1))) + +module InteractiveGlyphManagerService = + let getGlyphManager(textView: ITextView) = + textView.Properties.GetOrCreateSingletonProperty(typeof, fun () -> InteractivePromptGlyphTagger textView) + [] [] [] type InteractivePadController() as this = let mutable view = null - let mutable textView = null + //let mutable textView = null + let contentTypeRegistry = CompositionManager.Instance.GetExportedValue() + let textBufferFactory = CompositionManager.Instance.GetExportedValue() + let factory = CompositionManager.Instance.GetExportedValue() + let contentType = contentTypeRegistry.GetContentType(InteractiveContentTypeName.ContentTypeName) + let editorFormatMapService = CompositionManager.Instance.GetExportedValue() + //let appearanceCategory = Guid.NewGuid().ToString() + //let editorFormat = editorFormatMapService.GetEditorFormatMap(appearanceCategory) + //let resourceDictionary = editorFormat.GetProperties("Plain Text") + //resourceDictionary.[ClassificationFormatDefinition.TypefaceId] <- TextField.Font + //resourceDictionary.[ClassificationFormatDefinition.FontRenderingSizeId] <- 20 + //resourceDictionary.[ClassificationFormatDefinition.BackgroundBrushId] <- System.Windows.Media.Brushes.Black + //resourceDictionary.[ClassificationFormatDefinition.ForegroundColorId] <- System.Windows.Media.Brushes.Black + //editorFormat.SetProperties("Plain Text", resourceDictionary) + + let roles = factory.CreateTextViewRoleSet(PredefinedTextViewRoles.Analyzable, PredefinedTextViewRoles.Editable, PredefinedTextViewRoles.Interactive) + let textBuffer = textBufferFactory.CreateTextBuffer("", contentType) + + let textView = factory.CreateTextView(textBuffer, roles) + //textView.Background <- CGColor.CreateSrgb(nfloat 0.0, nfloat 0.0, nfloat 0.0, nfloat 0.0) do - let contentTypeRegistry = CompositionManager.Instance.GetExportedValue() - let textBufferFactory = CompositionManager.Instance.GetExportedValue() - let factory = CompositionManager.Instance.GetExportedValue() - let contentType = contentTypeRegistry.GetContentType(InteractiveContentTypeName.ContentTypeName) - let editorFormatMapService = CompositionManager.Instance.GetExportedValue() - //let appearanceCategory = Guid.NewGuid().ToString() - //let editorFormat = editorFormatMapService.GetEditorFormatMap(appearanceCategory) - //let resourceDictionary = editorFormat.GetProperties("Plain Text") - //resourceDictionary.[ClassificationFormatDefinition.TypefaceId] <- TextField.Font - //resourceDictionary.[ClassificationFormatDefinition.FontRenderingSizeId] <- 20 - //resourceDictionary.[ClassificationFormatDefinition.BackgroundBrushId] <- System.Windows.Media.Brushes.Black - //resourceDictionary.[ClassificationFormatDefinition.ForegroundColorId] <- System.Windows.Media.Brushes.Black - //editorFormat.SetProperties("Plain Text", resourceDictionary) - - let roles = factory.CreateTextViewRoleSet(PredefinedTextViewRoles.Analyzable, PredefinedTextViewRoles.Editable, PredefinedTextViewRoles.Interactive) - let textBuffer = textBufferFactory.CreateTextBuffer("", contentType) - - textView <- factory.CreateTextView(textBuffer, roles) - //textView.Background <- CGColor.CreateSrgb(nfloat 0.0, nfloat 0.0, nfloat 0.0, nfloat 0.0) textView.Options.SetOptionValue(DefaultTextViewOptions.UseVisibleWhitespaceId, false) //textView.Options.SetOptionValue(DefaultCocoaViewOptions.AppearanceCategory, appearanceCategory) textView.Options.SetOptionValue(DefaultTextViewHostOptions.ChangeTrackingId, false) @@ -241,7 +330,7 @@ type InteractivePadController() as this = textView.Options.SetOptionValue(DefaultTextViewHostOptions.OutliningMarginId, false) textView.Options.SetOptionValue(DefaultTextViewHostOptions.GlyphMarginId, true) textView.VisualElement.TranslatesAutoresizingMaskIntoConstraints <- false - textView.Properties.[typeof] <- this + //textView.Properties.[typeof] <- this let host = factory.CreateTextViewHost(textView, true) view <- host.HostControl @@ -255,6 +344,37 @@ type InteractivePadController() as this = if edit.Insert(position, text) then edit.Apply() |> ignore + member this.SetPrompt() = + this.FsiOutput "\n" + let buffer = textView.TextBuffer + //use edit = buffer.CreateEdit() + let snapshot = buffer.CurrentSnapshot + let lastLine = snapshot.GetLineFromLineNumber(snapshot.LineCount - 1) + //let span = new SnapshotSpan(lastLine.Start., lastLine.End) + let glyphManager = InteractiveGlyphManagerService.getGlyphManager(textView) + + glyphManager.AddPrompt lastLine.Start.Position + //(glyphManager :> ITagger).TagsChanged + + +[)>] +[] +[)>] +//[TagType(typeof(BreakpointDisabledGlyphTag))] +//[TagType(typeof(BreakpointInvalidGlyphTag))] +//[TagType(typeof(TracepointGlyphTag))] +//[TagType(typeof(TracepointDisabledGlyphTag))] +//[TagType(typeof(TracepointInvalidGlyphTag))] +//[TextViewRole(PredefinedTextViewRoles.Debuggable)] +type InteractivePromptGlyphTaggerProvider() = + interface IViewTaggerProvider with + //[Import] + //public ITextDocumentFactoryService TextDocumentFactoryService { get; set; } + + //public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag + member x.CreateTagger(textView, buffer) = + box(InteractivePromptGlyphTagger textView) :?> _ + type FSharpInteractivePad() as this = inherit MonoDevelop.Ide.Gui.PadContent() @@ -332,7 +452,7 @@ type FSharpInteractivePad() as this = promptReceived <- false let textReceived = ses.TextReceived.Subscribe(fun t -> Runtime.RunInMainThread(fun () -> controller.FsiOutput t) |> ignore) //let imageReceived = ses.ImageReceived.Subscribe(fun image -> Runtime.RunInMainThread(fun () -> renderImage image) |> Async.AwaitTask |> Async.RunSynchronously) - let promptReady = ses.PromptReady.Subscribe(fun () -> Runtime.RunInMainThread(fun () -> promptReceived <- true; setPrompt() ) |> ignore) + let promptReady = ses.PromptReady.Subscribe(fun () -> Runtime.RunInMainThread(fun () -> promptReceived <- true; controller.SetPrompt() ) |> ignore) ses.Exited.Add(fun _ -> textReceived.Dispose() From 186c0ad1c73f9bcc65caed79199a584320b5dae6 Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 3 Apr 2020 14:13:59 +0100 Subject: [PATCH 065/101] Allow input --- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 82 ++++++++++++++++++- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index 8fd897b33a8..a6d4c62eaed 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -55,6 +55,12 @@ open Microsoft.VisualStudio.Core.Imaging open Microsoft.VisualStudio.Text.Tagging open System.ComponentModel.Composition open Microsoft.VisualStudio.Imaging +open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion +open Microsoft.VisualStudio.Text +open Microsoft.VisualStudio.Commanding +open Microsoft.VisualStudio.Text.Editor +open Microsoft.VisualStudio.Text.Editor.Commanding.Commands +open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion [] module ColorHelpers = @@ -300,7 +306,7 @@ module InteractiveGlyphManagerService = [] [] [] -type InteractivePadController() as this = +type InteractivePadController(session: InteractiveSession) as this = let mutable view = null //let mutable textView = null let contentTypeRegistry = CompositionManager.Instance.GetExportedValue() @@ -321,6 +327,7 @@ type InteractivePadController() as this = let textBuffer = textBufferFactory.CreateTextBuffer("", contentType) let textView = factory.CreateTextView(textBuffer, roles) + let history = ShellHistory() //textView.Background <- CGColor.CreateSrgb(nfloat 0.0, nfloat 0.0, nfloat 0.0, nfloat 0.0) do textView.Options.SetOptionValue(DefaultTextViewOptions.UseVisibleWhitespaceId, false) @@ -330,12 +337,30 @@ type InteractivePadController() as this = textView.Options.SetOptionValue(DefaultTextViewHostOptions.OutliningMarginId, false) textView.Options.SetOptionValue(DefaultTextViewHostOptions.GlyphMarginId, true) textView.VisualElement.TranslatesAutoresizingMaskIntoConstraints <- false + textView.Properties.[typeof] <- this //textView.Properties.[typeof] <- this let host = factory.CreateTextViewHost(textView, true) view <- host.HostControl + let getActiveDocumentFileName () = + if IdeApp.Workbench.ActiveDocument <> null && FileService.isInsideFSharpFile() then + let docFileName = IdeApp.Workbench.ActiveDocument.FileName.ToString() + if docFileName <> null then + let directoryName = Path.GetDirectoryName docFileName + //ctx.WorkingFolder <- Some directoryName + Some docFileName + else None + else None + member this.View = view + member this.FsiInput text = + let fileName = getActiveDocumentFileName() + //input.Add text + history.Push text + session.SendInput (text + "\n") fileName + //session.SendInput + member this.FsiOutput text = let buffer = textView.TextBuffer use edit = buffer.CreateEdit() @@ -375,6 +400,10 @@ type InteractivePromptGlyphTaggerProvider() = member x.CreateTagger(textView, buffer) = box(InteractivePromptGlyphTagger textView) :?> _ +//module InteractiveControllerProvider = +// let getOrCreateController(textView: ITextView) = +// textView.Properties.GetOrCreateSingletonProperty(typeof, fun () -> new InteractivePadController()) + type FSharpInteractivePad() as this = inherit MonoDevelop.Ide.Gui.PadContent() @@ -443,11 +472,11 @@ type FSharpInteractivePad() as this = let pathToExe = Path.Combine(Reflection.Assembly.GetExecutingAssembly().Location |> Path.GetDirectoryName, "MonoDevelop.FSharpInteractive.Service.exe") |> ProcessArgumentBuilder.Quote - let controller = new InteractivePadController(); + let ses = InteractiveSession(pathToExe) + let controller = new InteractivePadController(ses) this.Host <- new GtkNSViewHost(controller.View) this.Host.ShowAll() - let ses = InteractiveSession(pathToExe) input.Clear() promptReceived <- false let textReceived = ses.TextReceived.Subscribe(fun t -> Runtime.RunInMainThread(fun () -> controller.FsiOutput t) |> ignore) @@ -681,7 +710,52 @@ type FSharpInteractivePad() as this = let file = dlg.SelectedFile //x.SendCommand ("#load @\"" + file.FullPath.ToString() + "\"") () - +[] +[] +//[] +[)>] +[] +type InteractivePadCompletionTypeCharHandler() = + interface ICommandHandler with + member x.DisplayName = "InteractivePadCompletionTypeCharHandler" + member x.GetCommandState _args = + CommandState.Available + + member x.ExecuteCommand(args, context) = + false + +[] +[] +//[] +[)>] +//[] +type InteractivePadCompletionReturnHandler() = + //interface ICommandHandler + //interface Microsoft.VisualStudio.Utilities.INamed with + // member x.DisplayName = "InteractivePadCompletionCommandHandler" + + interface ICommandHandler with + member x.DisplayName = "InteractivePadCompletionReturn" + member x.GetCommandState _args = + CommandState.Available + + member x.ExecuteCommand(args, context) = + let textView = args.TextView + let (controller: InteractivePadController) = downcast textView.Properties.[typeof] + let textBuffer = textView.TextBuffer + let snapshot = textBuffer.CurrentSnapshot + let position = textView.Caret.Position.BufferPosition.Position + let line = snapshot.GetLineFromPosition(position) + let start = line.Start.Position + let finish = line.End.Position + + let start = Math.Min(start, finish); + + let span = new Span(start, finish - start) + let text = snapshot.GetText(span).Trim() + controller.FsiOutput "\n" + controller.FsiInput text + true /// handles keypresses for F# Interactive //type FSharpFsiEditorCompletion() = // inherit TextEditorExtension() From a83ed6ca61d90542e17a53804d25e322296a7407 Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 3 Apr 2020 21:45:07 +0100 Subject: [PATCH 066/101] Add interactive completions --- .../Completion/CompletionUtils.fs | 2 +- .../src/FSharp.Editor/FSharp.Editor.fsproj | 4 +- .../src/FSharp.Editor/FSharp.addin.xml | 2 +- ...pletionService.fs => CompletionService.fs} | 184 ++++++++---------- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 5 +- 5 files changed, 89 insertions(+), 108 deletions(-) rename vsintegration/src/FSharp.Editor/VSMac/{InteractiveCompletionService.fs => CompletionService.fs} (72%) diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs index a3fc37d5ff8..581daaa1426 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs @@ -164,7 +164,7 @@ module internal CompletionUtils = let start = findStart position let endIndex = - if start <> position then + if start <> position && position < sourceText.Length then findEnd position else position diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 3a60789e66a..5f6b790b9f5 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -200,7 +200,7 @@ - {DFA822CA-CE06-4ECB-BA60-EB2A256E28F6} + {BAF30090-4E79-4D11-9E8D-30104E933B04} Microsoft.CodeAnalysis.ExternalAccess.FSharp @@ -260,7 +260,7 @@ {AF5FEAD5-B50E-4F07-A274-32F23D5C504D} MonoDevelop.FSharp.Shared - + diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index 52fc81a4406..c4de06436bb 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -55,7 +55,7 @@ - + diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveCompletionService.fs b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs similarity index 72% rename from vsintegration/src/FSharp.Editor/VSMac/InteractiveCompletionService.fs rename to vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs index 57927248111..0a5452d86ef 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveCompletionService.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs @@ -1,20 +1,4 @@ -// -// InteractiveCompletionService.fs -// -// Author: -// jasonimison -// -// Copyright (c) Microsoft Corporation. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. namespace Microsoft.VisualStudio.FSharp.Editor @@ -37,15 +21,13 @@ open Microsoft.CodeAnalysis.Classification open Microsoft.CodeAnalysis.Text; open Microsoft.VisualStudio.Text; open Microsoft.VisualStudio.Text.Adornments; - +open MonoDevelop.FSharp open FSharp.Compiler.SourceCodeServices +open System +open Microsoft.VisualStudio.Core.Imaging +open Microsoft.VisualStudio.Imaging - -type CompletionType = - | Document of Document - | Interactive - -type internal InteractiveCompletionService +type internal FSharpInteractiveCompletionService ( workspace: Workspace, checkerProvider: FSharpCheckerProvider, @@ -79,8 +61,8 @@ type internal InteractiveCompletionService .WithDefaultEnterKeyRule(enterKeyRule) [] -[, FSharpConstants.FSharpContentTypeName)>] -type internal FSharpCompletionSource +[, InteractiveContentTypeName.ContentTypeName)>] +type internal FSharpInteractiveCompletionSource (textView: ITextView, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider) = @@ -237,8 +219,30 @@ type internal FSharpCompletionSource /// A struct that holds completion items and applicable span let commitChars = [|' '; '='; ','; '.'; '<'; '>'; '('; ')'; '!'; ':'; '['; ']'; '|'|].ToImmutableArray() - let projectId = ProjectId.CreateNewId("F# Interactive") - let documentId = DocumentId.CreateNewId(projectId, "F# Interactive") + let imageCatalogGuid = Guid.Parse("ae27a6b0-e345-4288-96df-5eaf394ee369"); + let symbolStringToIcon = function + | "ActivePatternCase" -> ImageId(imageCatalogGuid, KnownImageIds.Enumeration) + | "Field" -> ImageId(imageCatalogGuid, KnownImageIds.Field) + | "UnionCase" -> ImageId(imageCatalogGuid, KnownImageIds.Union) + | "Class" -> ImageId(imageCatalogGuid, KnownImageIds.Class) + | "Delegate" -> ImageId(imageCatalogGuid, KnownImageIds.Delegate) + | "Constructor" -> ImageId(imageCatalogGuid, KnownImageIds.Method) + | "Event" -> ImageId(imageCatalogGuid, KnownImageIds.Event) + | "Property" -> ImageId(imageCatalogGuid, KnownImageIds.Property) + | "ExtensionMethod" -> ImageId(imageCatalogGuid, KnownImageIds.ExtensionMethod) + | "Method" -> ImageId(imageCatalogGuid, KnownImageIds.Method) + | "Operator" -> ImageId(imageCatalogGuid, KnownImageIds.Operator) + | "ClosureOrNestedFunction" -> ImageId(imageCatalogGuid, KnownImageIds.Method) + | "Val" -> ImageId(imageCatalogGuid, KnownImageIds.Field) + | "Enum" -> ImageId(imageCatalogGuid, KnownImageIds.Enumeration) + | "Interface" -> ImageId(imageCatalogGuid, KnownImageIds.Interface) + | "Module" -> ImageId(imageCatalogGuid, KnownImageIds.Module) + | "Namespace" -> ImageId(imageCatalogGuid, KnownImageIds.Namespace) + | "Record" -> ImageId(imageCatalogGuid, KnownImageIds.Class) + | "Union" -> ImageId(imageCatalogGuid, KnownImageIds.Union) + | "ValueType" -> ImageId(imageCatalogGuid, KnownImageIds.Structure) + | "Entity" -> ImageId(imageCatalogGuid, KnownImageIds.Class) + | _ -> ImageId(imageCatalogGuid, KnownImageIds.LocalVariable) interface IAsyncExpandingCompletionSource with member __.GetExpandedCompletionContextAsync(session, expander, initialTrigger, applicableToSpan, token) = @@ -248,78 +252,55 @@ type internal FSharpCompletionSource interface IAsyncCompletionSource with member this.GetCompletionContextAsync(session, trigger, triggerLocation, applicableToSpan, token) = - //let getProjectOptions completionType (sourceText: SourceText) = - //async { - // match! completionType with - // | Interactive -> - // let scriptProjectOptions, _ = checkerProvider.Checker.GetProjectOptionsFromScript("__FSI__.fsx", sourceText.ToFSharpSourceText()) |> Async.RunSynchronously - // "__FSI__.fsx", scriptProjectOptions, VersionStamp.Default - - // | Document document -> - - // let options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, token) |> Async.RunSynchronously - // match options with - // | Some (_parsingOptions, projectOptions) -> - // let version = - // match document.TryGetTextVersion() with - // | true, version -> version - // | _ -> VersionStamp.Create() - - // document.FilePath, projectOptions, version - - // | _ -> failwith "Could not get options" - //} - async { System.Diagnostics.Trace.WriteLine("GetCompletionContextAsync") - let document = session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() - - let sourceText = session.TextView.TextSnapshot.AsText() - //let document = - // match document with - // | null -> - // let workspace = new AdhocWorkspace() - // let projectInfo = ProjectInfo.Create(projectId, VersionStamp.Create(), "name", "name.dll", "F#") - // let project = workspace.AddProject(projectInfo) - // project.AddDocument("__FSI__.fsx", sourceText) - // | _ -> document - - let filePath, projectOptions, textVersion = - match document with - | null -> - let scriptProjectOptions, _ = checkerProvider.Checker.GetProjectOptionsFromScript("__FSI__.fsx", sourceText.ToFSharpSourceText()) |> Async.RunSynchronously - "__FSI__.fsx", scriptProjectOptions, VersionStamp.Default + let (interactiveSession: InteractiveSession) = downcast textView.Properties.[typeof] + let snapshot = session.TextView.TextBuffer.CurrentSnapshot + let line = snapshot.GetLineFromPosition(triggerLocation.Position) + let start = line.Start.Position + let finish = line.End.Position + + let span = new Span(start, finish - start) + let text = snapshot.GetText(span).Trim() + session.TextView.Properties.["PotentialCommitCharacters"] <- commitChars + interactiveSession.SendCompletionRequest text (triggerLocation.Position - start) + let! completions = interactiveSession.CompletionsReceived |> Async.AwaitEvent + //|> Async.RunSynchronously + //|> Array.map (fun c -> FsiMemberCompletionData(c.displayText, c.completionText, symbolStringToIcon c.icon)) + //|> Seq.cast + + return + match completions with + | [||] -> + Data.CompletionContext.Empty | _ -> - let options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, token) |> Async.RunSynchronously - match options with - | Some (_parsingOptions, projectOptions) -> - let version = - match document.TryGetTextVersion() with - | true, version -> version - | _ -> VersionStamp.Create() - - document.FilePath, projectOptions, version + let completions = + completions + |> Array.map (fun c -> + Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem(c.completionText, this, icon = ImageElement(symbolStringToIcon c.icon))) + Data.CompletionContext(completions.ToImmutableArray()) - | _ -> failwith "Could not get options" - + //let document = session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() + //let sourceText = session.TextView.TextSnapshot.AsText() //let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, token) //match options with //| Some (_parsingOptions, projectOptions) -> - let getAllSymbols(fileCheckResults: FSharpCheckFileResults) = - [] - //if settings.IntelliSense.IncludeSymbolsFromUnopenedNamespacesOrModules - //then assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies(fileCheckResults) - //else [] - - - session.TextView.Properties.["PotentialCommitCharacters"] <- commitChars - let! completions = FSharpCompletionProvider.ProvideCompletionsAsyncAux(this, checkerProvider.Checker, sourceText, triggerLocation.Position, projectOptions, filePath, textVersion.GetHashCode(), getAllSymbols, (*settings.LanguageServicePerformance*) LanguageServicePerformanceOptions.Default, (*settings.IntelliSense*) IntelliSenseOptions.Default) - match completions with - | Some completions' -> - return new Data.CompletionContext(completions'.ToImmutableArray()) - | None -> - return Data.CompletionContext.Empty + // let! textVersion = document.GetTextVersionAsync(token) |> liftTaskAsync + // let getAllSymbols(fileCheckResults: FSharpCheckFileResults) = + // [] + // //if settings.IntelliSense.IncludeSymbolsFromUnopenedNamespacesOrModules + // //then assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies(fileCheckResults) + // //else [] + + + // session.TextView.Properties.["PotentialCommitCharacters"] <- commitChars + // let! completions = FSharpCompletionProvider.ProvideCompletionsAsyncAux(this, checkerProvider.Checker, sourceText, triggerLocation.Position, projectOptions, document.FilePath, textVersion.GetHashCode(), getAllSymbols, (*settings.LanguageServicePerformance*) LanguageServicePerformanceOptions.Default, (*settings.IntelliSense*) IntelliSenseOptions.Default) + // match completions with + // | Some completions' -> + // return new Data.CompletionContext(completions'.ToImmutableArray()) + // | None -> + // return Data.CompletionContext.Empty //| _ -> // return Data.CompletionContext.Empty } |> RoslynHelpers.StartAsyncAsTask token @@ -371,13 +352,12 @@ type internal FSharpCompletionSource let document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges() let getInfo() = - match document with - | null -> - (documentId, "__FSI__.fsx", []) - | _ -> - let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) - (document.Id, document.FilePath, defines) + //let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) + let projectId = ProjectId.CreateNewId() + let documentId = DocumentId.CreateNewId(projectId) + (documentId, "temp.fsx", []) + let sourceText = triggerLocation.Snapshot.AsText() let shouldTrigger = FSharpCompletionProvider.ShouldTriggerCompletionAux(sourceText, triggerLocation.Position, trigger, getInfo, (*settings.IntelliSense*) IntelliSenseOptions.Default) @@ -394,9 +374,9 @@ type internal FSharpCompletionSource [)>] [)>] -[] -[] -type internal CompletionSourceProvider +[] +[] +type internal InteractiveCompletionSourceProvider [] ( checkerProvider: FSharpCheckerProvider, @@ -407,7 +387,7 @@ type internal CompletionSourceProvider interface IAsyncCompletionSourceProvider with member __.GetOrCreate(textView) = System.Diagnostics.Trace.WriteLine("Completion .ctor") - new FSharpCompletionSource(textView, checkerProvider, projectInfoManager, assemblyContentProvider) :> _ + new FSharpInteractiveCompletionSource(textView, checkerProvider, projectInfoManager, assemblyContentProvider) :> _ interface IAsyncCompletionCommitManagerProvider with member __.GetOrCreate(_textView) = diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index a6d4c62eaed..547e0b0288d 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -23,7 +23,7 @@ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -namespace FSharp.Editor +namespace Microsoft.VisualStudio.FSharp.Editor open System open System.IO @@ -232,7 +232,7 @@ type InteractiveGlyphFactory(imageId:ImageId, imageService:IImageService) = imageCache <- Some(imageService.GetImage (imageId) :?> AppKit.NSImage) let imageView = AppKit.NSImageView.FromImage imageCache.Value imageView.SetFrameSize (imageView.FittingSize) - Some (imageView :> obj) + Some (box imageView) | _ -> None |> Option.toObj @@ -338,6 +338,7 @@ type InteractivePadController(session: InteractiveSession) as this = textView.Options.SetOptionValue(DefaultTextViewHostOptions.GlyphMarginId, true) textView.VisualElement.TranslatesAutoresizingMaskIntoConstraints <- false textView.Properties.[typeof] <- this + textView.Properties.[typeof] <- session //textView.Properties.[typeof] <- this let host = factory.CreateTextViewHost(textView, true) view <- host.HostControl From 0699dcc54f24d5bef6898e47fedbfae891744eb0 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 6 Apr 2020 10:37:08 +0100 Subject: [PATCH 067/101] Fix return key when intellisense is active --- .../FSharp.Editor/VSMac/CompletionService.fs | 26 ------------------- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 11 +++++--- 2 files changed, 7 insertions(+), 30 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs index 0a5452d86ef..2c9c8ddf5ab 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs @@ -265,9 +265,6 @@ type internal FSharpInteractiveCompletionSource session.TextView.Properties.["PotentialCommitCharacters"] <- commitChars interactiveSession.SendCompletionRequest text (triggerLocation.Position - start) let! completions = interactiveSession.CompletionsReceived |> Async.AwaitEvent - //|> Async.RunSynchronously - //|> Array.map (fun c -> FsiMemberCompletionData(c.displayText, c.completionText, symbolStringToIcon c.icon)) - //|> Seq.cast return match completions with @@ -280,29 +277,6 @@ type internal FSharpInteractiveCompletionSource Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem(c.completionText, this, icon = ImageElement(symbolStringToIcon c.icon))) Data.CompletionContext(completions.ToImmutableArray()) - //let document = session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() - - //let sourceText = session.TextView.TextSnapshot.AsText() - //let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, token) - //match options with - //| Some (_parsingOptions, projectOptions) -> - // let! textVersion = document.GetTextVersionAsync(token) |> liftTaskAsync - // let getAllSymbols(fileCheckResults: FSharpCheckFileResults) = - // [] - // //if settings.IntelliSense.IncludeSymbolsFromUnopenedNamespacesOrModules - // //then assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies(fileCheckResults) - // //else [] - - - // session.TextView.Properties.["PotentialCommitCharacters"] <- commitChars - // let! completions = FSharpCompletionProvider.ProvideCompletionsAsyncAux(this, checkerProvider.Checker, sourceText, triggerLocation.Position, projectOptions, document.FilePath, textVersion.GetHashCode(), getAllSymbols, (*settings.LanguageServicePerformance*) LanguageServicePerformanceOptions.Default, (*settings.IntelliSense*) IntelliSenseOptions.Default) - // match completions with - // | Some completions' -> - // return new Data.CompletionContext(completions'.ToImmutableArray()) - // | None -> - // return Data.CompletionContext.Empty - //| _ -> - // return Data.CompletionContext.Empty } |> RoslynHelpers.StartAsyncAsTask token /// diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index 547e0b0288d..fe09366310f 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -61,6 +61,7 @@ open Microsoft.VisualStudio.Commanding open Microsoft.VisualStudio.Text.Editor open Microsoft.VisualStudio.Text.Editor.Commanding.Commands open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion +open Microsoft.VisualStudio.Language.Intellisense [] module ColorHelpers = @@ -730,10 +731,9 @@ type InteractivePadCompletionTypeCharHandler() = //[] [)>] //[] -type InteractivePadCompletionReturnHandler() = - //interface ICommandHandler - //interface Microsoft.VisualStudio.Utilities.INamed with - // member x.DisplayName = "InteractivePadCompletionCommandHandler" +type InteractivePadCompletionReturnHandler + [] + ( completionBroker:ICompletionBroker ) = interface ICommandHandler with member x.DisplayName = "InteractivePadCompletionReturn" @@ -741,6 +741,9 @@ type InteractivePadCompletionReturnHandler() = CommandState.Available member x.ExecuteCommand(args, context) = + if completionBroker.IsCompletionActive(args.TextView) then + false + else let textView = args.TextView let (controller: InteractivePadController) = downcast textView.Properties.[typeof] let textBuffer = textView.TextBuffer From a7d25772bab1f365d5eb753ecdd45cc48a4921bc Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 9 Apr 2020 10:37:22 +0100 Subject: [PATCH 068/101] Add InteractiveClassification --- .../Classification/ClassificationService.fs | 6 +- .../src/FSharp.Editor/FSharp.Editor.fsproj | 2 + .../VSMac/InteractiveClassificationService.fs | 78 +++++++++++++++++++ .../src/FSharp.Editor/VSMac/InteractivePad.fs | 54 +++++++++---- .../VSMac/InteractiveWorkspace.fs | 77 ++++++++++++++++++ 5 files changed, 198 insertions(+), 19 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs create mode 100644 vsintegration/src/FSharp.Editor/VSMac/InteractiveWorkspace.fs diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs index 5cc0ad56120..fc9a4e64440 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs @@ -17,7 +17,7 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Classification open Microsoft.VisualStudio.Text.Classification open System.Windows.Media open MonoDevelop.Core - +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor // IEditorClassificationService is marked as Obsolete, but is still supported. The replacement (IClassificationService) // is internal to Microsoft.CodeAnalysis.Workspaces which we don't have internals visible to. Rather than add yet another // IVT, we'll maintain the status quo. @@ -62,7 +62,7 @@ module internal FSharpClassificationTypes = | SemanticClassificationType.Operator -> Operator | SemanticClassificationType.Disposable -> Disposable -[)>] +[] type internal FSharpClassificationService [] ( @@ -110,5 +110,3 @@ type internal FSharpClassificationService // Do not perform classification if we don't have project options (#defines matter) member __.AdjustStaleClassification(_: SourceText, classifiedSpan: ClassifiedSpan) : ClassifiedSpan = classifiedSpan - - diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 5f6b790b9f5..1537f0e7b8e 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -254,6 +254,7 @@ CoreUtility CoreUtility + @@ -261,6 +262,7 @@ MonoDevelop.FSharp.Shared + diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs new file mode 100644 index 00000000000..4c9c9f7280d --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs @@ -0,0 +1,78 @@ +// +// InteractiveClassificationService.fs +// +// Author: +// jasonimison +// +// Copyright (c) 2020 Microsoft +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +namespace Microsoft.VisualStudio.FSharp.Editor + +open System +open System.Composition +open System.Collections.Generic +open System.Diagnostics +open System.Threading + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.Classification +open Microsoft.CodeAnalysis.Editor +open Microsoft.CodeAnalysis.Host.Mef +open Microsoft.CodeAnalysis.Text +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Classification +open Microsoft.VisualStudio.Text.Classification +open System.Windows.Media +open MonoDevelop.Core +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor + +//[, FSharpContentTypeNames.FSharpInteractiveContentType)>] +[] +type internal FSharpInteractiveClassificationService + [] + ( + service: IFSharpClassificationService + ) = + interface IFSharpInteractiveClassificationService with + + member __.AddLexicalClassifications(sourceText: SourceText, textSpan: TextSpan, result: List, cancellationToken: CancellationToken) = + let line = sourceText.Lines.GetLineFromPosition(textSpan.Start).LineNumber + + if FSharpInteractivePad.Fsi.Value.Controller.Value.IsInputLine(line) then + service.AddLexicalClassifications(sourceText, textSpan, result, cancellationToken) + + member __.AddSyntacticClassificationsAsync(document: Document, textSpan: TextSpan, result: List, cancellationToken: CancellationToken) = + match document.TryGetText() with + | true, sourceText -> + let line = sourceText.Lines.GetLineFromPosition(textSpan.Start).LineNumber + + if FSharpInteractivePad.Fsi.Value.Controller.Value.IsInputLine(line) then + //let service = document.Project.LanguageServices.GetService(); + + service.AddSyntacticClassificationsAsync(document, textSpan, result, cancellationToken) + else + Tasks.Task.CompletedTask + | false, _ -> Tasks.Task.CompletedTask + + //member __.AddSemanticClassificationsAsync(document: Document, textSpan: TextSpan, result: List, cancellationToken: CancellationToken) = + // System.Threading.Tasks.Task.CompletedTask + + // Do not perform classification if we don't have project options (#defines matter) + member __.AdjustStaleClassification(_: SourceText, classifiedSpan: ClassifiedSpan) : ClassifiedSpan = classifiedSpan + diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index fe09366310f..3b584af24e3 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -62,7 +62,13 @@ open Microsoft.VisualStudio.Text.Editor open Microsoft.VisualStudio.Text.Editor.Commanding.Commands open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion open Microsoft.VisualStudio.Language.Intellisense - +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.Text +open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.Text +open Microsoft.VisualStudio.Text.Editor +open Microsoft.VisualStudio.Threading +open FSharp.Editor [] module ColorHelpers = let strToColor s = @@ -217,7 +223,7 @@ module InteractiveContentTypeName = type InteractiveContentTypeDefinition() = [] [] - [] + [] member val InteractiveContentTypeDefinition: Microsoft.VisualStudio.Utilities.ContentTypeDefinition = null with get, set type InteractivePromptGlyphTag() = interface IGlyphTag @@ -315,22 +321,26 @@ type InteractivePadController(session: InteractiveSession) as this = let factory = CompositionManager.Instance.GetExportedValue() let contentType = contentTypeRegistry.GetContentType(InteractiveContentTypeName.ContentTypeName) let editorFormatMapService = CompositionManager.Instance.GetExportedValue() - //let appearanceCategory = Guid.NewGuid().ToString() - //let editorFormat = editorFormatMapService.GetEditorFormatMap(appearanceCategory) - //let resourceDictionary = editorFormat.GetProperties("Plain Text") - //resourceDictionary.[ClassificationFormatDefinition.TypefaceId] <- TextField.Font - //resourceDictionary.[ClassificationFormatDefinition.FontRenderingSizeId] <- 20 - //resourceDictionary.[ClassificationFormatDefinition.BackgroundBrushId] <- System.Windows.Media.Brushes.Black - //resourceDictionary.[ClassificationFormatDefinition.ForegroundColorId] <- System.Windows.Media.Brushes.Black - //editorFormat.SetProperties("Plain Text", resourceDictionary) - - let roles = factory.CreateTextViewRoleSet(PredefinedTextViewRoles.Analyzable, PredefinedTextViewRoles.Editable, PredefinedTextViewRoles.Interactive) + + let appearanceCategory = Guid.NewGuid().ToString() + let editorFormat = editorFormatMapService.GetEditorFormatMap(appearanceCategory) + let resourceDictionary = editorFormat.GetProperties("Plain Text") + + let roles = factory.CreateTextViewRoleSet(PredefinedTextViewRoles.Editable, PredefinedTextViewRoles.Interactive, PredefinedTextViewRoles.Document) let textBuffer = textBufferFactory.CreateTextBuffer("", contentType) let textView = factory.CreateTextView(textBuffer, roles) + let workspace = new InteractiveWorkspace() + //let (workspace: MiscellaneousFilesWorkspace) = downcast IdeApp.TypeSystemService.GetWorkspaceInternal(null) let history = ShellHistory() //textView.Background <- CGColor.CreateSrgb(nfloat 0.0, nfloat 0.0, nfloat 0.0, nfloat 0.0) do + //resourceDictionary.[ClassificationFormatDefinition.TypefaceId] <- TextField.Font + resourceDictionary.[ClassificationFormatDefinition.FontRenderingSizeId] <- 20 + resourceDictionary.[ClassificationFormatDefinition.BackgroundBrushId] <- System.Windows.Media.Brushes.Black + resourceDictionary.[ClassificationFormatDefinition.ForegroundColorId] <- System.Windows.Media.Brushes.White + editorFormat.SetProperties("Plain Text", resourceDictionary) + textView.Options.SetOptionValue(DefaultTextViewOptions.UseVisibleWhitespaceId, false) //textView.Options.SetOptionValue(DefaultCocoaViewOptions.AppearanceCategory, appearanceCategory) textView.Options.SetOptionValue(DefaultTextViewHostOptions.ChangeTrackingId, false) @@ -343,6 +353,10 @@ type InteractivePadController(session: InteractiveSession) as this = //textView.Properties.[typeof] <- this let host = factory.CreateTextViewHost(textView, true) view <- host.HostControl + // Add the view to a workspace so that Roslyn can fetch LanguageServices + // Note: this fake file name must end with .fs, not .fsx so that we don't get the MiscellaneousFilesWorkspace + //workspace.OnDocumentOpened("interactive.fsx", textBuffer) + workspace.CreateDocument(textBuffer) let getActiveDocumentFileName () = if IdeApp.Workbench.ActiveDocument <> null && FileService.isInsideFSharpFile() then @@ -354,14 +368,22 @@ type InteractivePadController(session: InteractiveSession) as this = else None else None + let inputLines = HashSet() + member this.View = view + member this.IsInputLine(line:int) = + let buffer = textView.TextBuffer + let snapshot = buffer.CurrentSnapshot + inputLines.Contains line || line = snapshot.LineCount - 1 + member this.FsiInput text = let fileName = getActiveDocumentFileName() - //input.Add text history.Push text + let buffer = textView.TextBuffer + let snapshot = buffer.CurrentSnapshot + inputLines.Add(snapshot.LineCount - 1) |> ignore session.SendInput (text + "\n") fileName - //session.SendInput member this.FsiOutput text = let buffer = textView.TextBuffer @@ -500,7 +522,9 @@ type FSharpInteractivePad() as this = ses.StartReceiving() //editor.GrabFocus() Some(ses) - with _exn -> None + with + | :? Exception as e -> + None let mutable session = None diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveWorkspace.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveWorkspace.fs new file mode 100644 index 00000000000..c6843c81841 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveWorkspace.fs @@ -0,0 +1,77 @@ +// +// InteractiveWorkspace.fs +// +// Author: +// jasonimison +// +// Copyright (c) 2020 Microsoft +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +namespace FSharp.Editor + +open Microsoft.CodeAnalysis +open MonoDevelop.Ide.Composition +open System + +open System +open System.Collections.Concurrent +open System.Collections.Immutable +open System.ComponentModel.Composition +open System.IO +open System.Linq +open System.Threading +open System.Threading.Tasks +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.CSharp +open Microsoft.CodeAnalysis.Host +open Microsoft.CodeAnalysis.Scripting +open Microsoft.CodeAnalysis.Text +open Microsoft.VisualStudio.Composition +open Microsoft.VisualStudio.Text +open Mono.Addins +open MonoDevelop.Core +open MonoDevelop.Ide.Composition +type InteractiveWorkspace() = + inherit Workspace(CompositionManager.Instance.HostServices, WorkspaceKind.MiscellaneousFiles) with + member x.CreateDocument(buffer: ITextBuffer) = + let projectId = ProjectId.CreateNewId() + let name = "interactive.fsx" + let documentId = DocumentId.CreateNewId(projectId, name) + let container = buffer.AsTextContainer() + + let projectInfo = + ProjectInfo.Create( + projectId, + VersionStamp.Create(), + name = name, + assemblyName = "interactive.dll", + language = LanguageNames.FSharp) + + base.OnProjectAdded(projectInfo) + let documentInfo = + DocumentInfo.Create( + documentId, + name, + Array.empty, + sourceCodeKind = SourceCodeKind.Script, + filePath = name, + loader = TextLoader.From(buffer.AsTextContainer(), VersionStamp.Create())) + + base.OnDocumentAdded(documentInfo) + base.OnDocumentOpened(documentId, container) From 3b89708178f2345c0cc3cdd0be99d0f6b3c7ebd3 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 15 Apr 2020 15:53:46 +0100 Subject: [PATCH 069/101] Fix interactive classification --- .../Classification/ClassificationService.fs | 2 +- .../FSharp.Editor/VSMac/CompletionService.fs | 4 +- .../VSMac/InteractiveClassificationService.fs | 11 +++-- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 44 +++++++++---------- .../VSMac/InteractiveWorkspace.fs | 2 +- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs index fc9a4e64440..2e858a8915e 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs @@ -62,7 +62,7 @@ module internal FSharpClassificationTypes = | SemanticClassificationType.Operator -> Operator | SemanticClassificationType.Disposable -> Disposable -[] +[)>] type internal FSharpClassificationService [] ( diff --git a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs index 2c9c8ddf5ab..012eae0322e 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs @@ -61,7 +61,7 @@ type internal FSharpInteractiveCompletionService .WithDefaultEnterKeyRule(enterKeyRule) [] -[, InteractiveContentTypeName.ContentTypeName)>] +[, FSharpContentTypeNames.FSharpInteractiveContentType)>] type internal FSharpInteractiveCompletionSource (textView: ITextView, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider) = @@ -349,7 +349,7 @@ type internal FSharpInteractiveCompletionSource [)>] [)>] [] -[] +[] type internal InteractiveCompletionSourceProvider [] ( diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs index 4c9c9f7280d..b7dddd87bc5 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs @@ -43,7 +43,8 @@ open MonoDevelop.Core open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor //[, FSharpContentTypeNames.FSharpInteractiveContentType)>] -[] +//[] +[)>] type internal FSharpInteractiveClassificationService [] ( @@ -52,12 +53,14 @@ type internal FSharpInteractiveClassificationService interface IFSharpInteractiveClassificationService with member __.AddLexicalClassifications(sourceText: SourceText, textSpan: TextSpan, result: List, cancellationToken: CancellationToken) = - let line = sourceText.Lines.GetLineFromPosition(textSpan.Start).LineNumber + //let line = sourceText.Lines.GetLineFromPosition(textSpan.Start).LineNumber - if FSharpInteractivePad.Fsi.Value.Controller.Value.IsInputLine(line) then - service.AddLexicalClassifications(sourceText, textSpan, result, cancellationToken) + //if FSharpInteractivePad.Fsi.Value.Controller.Value.IsInputLine(line) then + //service.AddLexicalClassifications(sourceText, textSpan, result, cancellationToken) + () member __.AddSyntacticClassificationsAsync(document: Document, textSpan: TextSpan, result: List, cancellationToken: CancellationToken) = + //Tasks.Task.CompletedTask match document.TryGetText() with | true, sourceText -> let line = sourceText.Lines.GetLineFromPosition(textSpan.Start).LineNumber diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index 3b584af24e3..9e221276320 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -69,6 +69,7 @@ open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor open Microsoft.VisualStudio.Threading open FSharp.Editor +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor [] module ColorHelpers = let strToColor s = @@ -216,15 +217,7 @@ type ShellHistory() = else Some history.[nextDown] -module InteractiveContentTypeName = - [] - let ContentTypeName = "F# Interactive" -type InteractiveContentTypeDefinition() = - [] - [] - [] - member val InteractiveContentTypeDefinition: Microsoft.VisualStudio.Utilities.ContentTypeDefinition = null with get, set type InteractivePromptGlyphTag() = interface IGlyphTag @@ -245,7 +238,7 @@ type InteractiveGlyphFactory(imageId:ImageId, imageService:IImageService) = [)>] [] -[] +[] [)>] //[] type InteractiveGlyphFactoryProvider() as this = @@ -311,7 +304,7 @@ module InteractiveGlyphManagerService = textView.Properties.GetOrCreateSingletonProperty(typeof, fun () -> InteractivePromptGlyphTagger textView) [] -[] +[] [] type InteractivePadController(session: InteractiveSession) as this = let mutable view = null @@ -319,12 +312,12 @@ type InteractivePadController(session: InteractiveSession) as this = let contentTypeRegistry = CompositionManager.Instance.GetExportedValue() let textBufferFactory = CompositionManager.Instance.GetExportedValue() let factory = CompositionManager.Instance.GetExportedValue() - let contentType = contentTypeRegistry.GetContentType(InteractiveContentTypeName.ContentTypeName) - let editorFormatMapService = CompositionManager.Instance.GetExportedValue() + let contentType = contentTypeRegistry.GetContentType(FSharpContentTypeNames.FSharpInteractiveContentType) + //let editorFormatMapService = CompositionManager.Instance.GetExportedValue() - let appearanceCategory = Guid.NewGuid().ToString() - let editorFormat = editorFormatMapService.GetEditorFormatMap(appearanceCategory) - let resourceDictionary = editorFormat.GetProperties("Plain Text") + //let appearanceCategory = Guid.NewGuid().ToString() + //let editorFormat = editorFormatMapService.GetEditorFormatMap(appearanceCategory) + //let resourceDictionary = editorFormat.GetProperties("Plain Text") let roles = factory.CreateTextViewRoleSet(PredefinedTextViewRoles.Editable, PredefinedTextViewRoles.Interactive, PredefinedTextViewRoles.Document) let textBuffer = textBufferFactory.CreateTextBuffer("", contentType) @@ -336,10 +329,10 @@ type InteractivePadController(session: InteractiveSession) as this = //textView.Background <- CGColor.CreateSrgb(nfloat 0.0, nfloat 0.0, nfloat 0.0, nfloat 0.0) do //resourceDictionary.[ClassificationFormatDefinition.TypefaceId] <- TextField.Font - resourceDictionary.[ClassificationFormatDefinition.FontRenderingSizeId] <- 20 - resourceDictionary.[ClassificationFormatDefinition.BackgroundBrushId] <- System.Windows.Media.Brushes.Black - resourceDictionary.[ClassificationFormatDefinition.ForegroundColorId] <- System.Windows.Media.Brushes.White - editorFormat.SetProperties("Plain Text", resourceDictionary) + //resourceDictionary.[ClassificationFormatDefinition.FontRenderingSizeId] <- 20 + //resourceDictionary.[ClassificationFormatDefinition.BackgroundBrushId] <- System.Windows.Media.Brushes.Black + //resourceDictionary.[ClassificationFormatDefinition.ForegroundColorId] <- System.Windows.Media.Brushes.White + //editorFormat.SetProperties("Plain Text", resourceDictionary) textView.Options.SetOptionValue(DefaultTextViewOptions.UseVisibleWhitespaceId, false) //textView.Options.SetOptionValue(DefaultCocoaViewOptions.AppearanceCategory, appearanceCategory) @@ -375,14 +368,14 @@ type InteractivePadController(session: InteractiveSession) as this = member this.IsInputLine(line:int) = let buffer = textView.TextBuffer let snapshot = buffer.CurrentSnapshot - inputLines.Contains line || line = snapshot.LineCount - 1 + inputLines.Contains line member this.FsiInput text = let fileName = getActiveDocumentFileName() history.Push text let buffer = textView.TextBuffer let snapshot = buffer.CurrentSnapshot - inputLines.Add(snapshot.LineCount - 1) |> ignore + //inputLines.Add(snapshot.LineCount - 1) |> ignore session.SendInput (text + "\n") fileName member this.FsiOutput text = @@ -401,13 +394,14 @@ type InteractivePadController(session: InteractiveSession) as this = let lastLine = snapshot.GetLineFromLineNumber(snapshot.LineCount - 1) //let span = new SnapshotSpan(lastLine.Start., lastLine.End) let glyphManager = InteractiveGlyphManagerService.getGlyphManager(textView) + inputLines.Add(snapshot.LineCount - 1) |> ignore glyphManager.AddPrompt lastLine.Start.Position //(glyphManager :> ITagger).TagsChanged [)>] -[] +[] [)>] //[TagType(typeof(BreakpointDisabledGlyphTag))] //[TagType(typeof(BreakpointInvalidGlyphTag))] @@ -498,6 +492,7 @@ type FSharpInteractivePad() as this = |> ProcessArgumentBuilder.Quote let ses = InteractiveSession(pathToExe) let controller = new InteractivePadController(ses) + this.Controller <- Some controller this.Host <- new GtkNSViewHost(controller.View) this.Host.ShowAll() @@ -737,7 +732,7 @@ type FSharpInteractivePad() as this = //x.SendCommand ("#load @\"" + file.FullPath.ToString() + "\"") () [] -[] +[] //[] [)>] [] @@ -751,7 +746,7 @@ type InteractivePadCompletionTypeCharHandler() = false [] -[] +[] //[] [)>] //[] @@ -770,6 +765,7 @@ type InteractivePadCompletionReturnHandler else let textView = args.TextView let (controller: InteractivePadController) = downcast textView.Properties.[typeof] + let textBuffer = textView.TextBuffer let snapshot = textBuffer.CurrentSnapshot let position = textView.Caret.Position.BufferPosition.Position diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveWorkspace.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveWorkspace.fs index c6843c81841..9d7fa1457c5 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveWorkspace.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveWorkspace.fs @@ -61,7 +61,7 @@ type InteractiveWorkspace() = VersionStamp.Create(), name = name, assemblyName = "interactive.dll", - language = LanguageNames.FSharp) + language = "F# Interactive") base.OnProjectAdded(projectInfo) let documentInfo = From db5b4e05f16a3287506e7ee5b032bd6d149394bc Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 16 Apr 2020 09:48:42 +0100 Subject: [PATCH 070/101] 1 based column index for interactive completion --- vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs | 6 ++---- .../FSharp.Editor/VSMac/InteractiveClassificationService.fs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs index 012eae0322e..13d0f517712 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs @@ -26,6 +26,7 @@ open FSharp.Compiler.SourceCodeServices open System open Microsoft.VisualStudio.Core.Imaging open Microsoft.VisualStudio.Imaging +open FSharp.Compiler.Range type internal FSharpInteractiveCompletionService ( @@ -263,7 +264,7 @@ type internal FSharpInteractiveCompletionSource let span = new Span(start, finish - start) let text = snapshot.GetText(span).Trim() session.TextView.Properties.["PotentialCommitCharacters"] <- commitChars - interactiveSession.SendCompletionRequest text (triggerLocation.Position - start) + interactiveSession.SendCompletionRequest text (triggerLocation.Position - start + 1) let! completions = interactiveSession.CompletionsReceived |> Async.AwaitEvent return @@ -326,7 +327,6 @@ type internal FSharpInteractiveCompletionSource let document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges() let getInfo() = - //let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) let projectId = ProjectId.CreateNewId() let documentId = DocumentId.CreateNewId(projectId) (documentId, "temp.fsx", []) @@ -360,10 +360,8 @@ type internal InteractiveCompletionSourceProvider interface IAsyncCompletionSourceProvider with member __.GetOrCreate(textView) = - System.Diagnostics.Trace.WriteLine("Completion .ctor") new FSharpInteractiveCompletionSource(textView, checkerProvider, projectInfoManager, assemblyContentProvider) :> _ interface IAsyncCompletionCommitManagerProvider with member __.GetOrCreate(_textView) = - System.Diagnostics.Trace.WriteLine("GetOrCreate FSharpAsyncCompletionCommitManager") FSharpAsyncCompletionCommitManager() :> _ diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs index b7dddd87bc5..0e34f46e839 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs @@ -58,7 +58,7 @@ type internal FSharpInteractiveClassificationService //if FSharpInteractivePad.Fsi.Value.Controller.Value.IsInputLine(line) then //service.AddLexicalClassifications(sourceText, textSpan, result, cancellationToken) () - + member __.AddSyntacticClassificationsAsync(document: Document, textSpan: TextSpan, result: List, cancellationToken: CancellationToken) = //Tasks.Task.CompletedTask match document.TryGetText() with From 86755f0c74edfbbabdabdc3a8b7d6a8bb05b5c97 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 16 Apr 2020 11:34:57 +0100 Subject: [PATCH 071/101] Get debugger tooltips for LocalName classification --- .../src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs b/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs index cf37cf08aa6..8d76245ab72 100644 --- a/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs +++ b/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs @@ -32,6 +32,7 @@ type internal FSharpLanguageDebugInfoService [](projectInf | ClassificationTypeNames.StringLiteral -> Some(token.TextSpan) + | ClassificationTypeNames.LocalName | ClassificationTypeNames.Identifier -> let textLine = sourceText.Lines.GetLineFromPosition(position) let textLinePos = sourceText.Lines.GetLinePosition(position) From a06940b659ec36053f3586d504d914ac03461fbf Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 16 Apr 2020 13:05:15 +0100 Subject: [PATCH 072/101] Remove dependency on FSharpBinding --- vsintegration/src/FSharp.Editor/FSharp.addin.xml | 4 ++-- vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index c4de06436bb..36af081700d 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -44,8 +44,8 @@ extensions=".fs,.fsi,.fsx,.fsscript,.sketchfs" singleLineCommentTag="//" blockCommentStartTag="(*" - blockCommentEndTag="*)" - codeDomType="FSharp.Compiler.CodeDom.FSharpCleanCodeProvider" /> + blockCommentEndTag="*)" /> + diff --git a/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs b/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs index 0cf621d0ad6..ac8319a4f98 100644 --- a/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs +++ b/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs @@ -12,5 +12,5 @@ open Mono.Addins [] [] -[] +//[] () \ No newline at end of file From 62b93f22fbda50a7f87b18eda5f57a8f275cfac4 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 16 Apr 2020 17:07:09 +0100 Subject: [PATCH 073/101] Convert interactive completions to FSharpDeclarationItem API --- .../FSharp.Editor/VSMac/CompletionService.fs | 26 +------------------ .../FSharp.Editor/VSMac/InteractiveSession.fs | 5 +++- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs index 13d0f517712..b2d48d64d16 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs @@ -221,36 +221,12 @@ type internal FSharpInteractiveCompletionSource let commitChars = [|' '; '='; ','; '.'; '<'; '>'; '('; ')'; '!'; ':'; '['; ']'; '|'|].ToImmutableArray() let imageCatalogGuid = Guid.Parse("ae27a6b0-e345-4288-96df-5eaf394ee369"); - let symbolStringToIcon = function - | "ActivePatternCase" -> ImageId(imageCatalogGuid, KnownImageIds.Enumeration) - | "Field" -> ImageId(imageCatalogGuid, KnownImageIds.Field) - | "UnionCase" -> ImageId(imageCatalogGuid, KnownImageIds.Union) - | "Class" -> ImageId(imageCatalogGuid, KnownImageIds.Class) - | "Delegate" -> ImageId(imageCatalogGuid, KnownImageIds.Delegate) - | "Constructor" -> ImageId(imageCatalogGuid, KnownImageIds.Method) - | "Event" -> ImageId(imageCatalogGuid, KnownImageIds.Event) - | "Property" -> ImageId(imageCatalogGuid, KnownImageIds.Property) - | "ExtensionMethod" -> ImageId(imageCatalogGuid, KnownImageIds.ExtensionMethod) - | "Method" -> ImageId(imageCatalogGuid, KnownImageIds.Method) - | "Operator" -> ImageId(imageCatalogGuid, KnownImageIds.Operator) - | "ClosureOrNestedFunction" -> ImageId(imageCatalogGuid, KnownImageIds.Method) - | "Val" -> ImageId(imageCatalogGuid, KnownImageIds.Field) - | "Enum" -> ImageId(imageCatalogGuid, KnownImageIds.Enumeration) - | "Interface" -> ImageId(imageCatalogGuid, KnownImageIds.Interface) - | "Module" -> ImageId(imageCatalogGuid, KnownImageIds.Module) - | "Namespace" -> ImageId(imageCatalogGuid, KnownImageIds.Namespace) - | "Record" -> ImageId(imageCatalogGuid, KnownImageIds.Class) - | "Union" -> ImageId(imageCatalogGuid, KnownImageIds.Union) - | "ValueType" -> ImageId(imageCatalogGuid, KnownImageIds.Structure) - | "Entity" -> ImageId(imageCatalogGuid, KnownImageIds.Class) - | _ -> ImageId(imageCatalogGuid, KnownImageIds.LocalVariable) interface IAsyncExpandingCompletionSource with member __.GetExpandedCompletionContextAsync(session, expander, initialTrigger, applicableToSpan, token) = let ctx = Data.CompletionContext.Empty Task.FromResult ctx - interface IAsyncCompletionSource with member this.GetCompletionContextAsync(session, trigger, triggerLocation, applicableToSpan, token) = async { @@ -275,7 +251,7 @@ type internal FSharpInteractiveCompletionSource let completions = completions |> Array.map (fun c -> - Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem(c.completionText, this, icon = ImageElement(symbolStringToIcon c.icon))) + Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem(c.completionText, this, icon = ImageElement(GlyphHelper.getImageId c.icon))) Data.CompletionContext(completions.ToImmutableArray()) } |> RoslynHelpers.StartAsyncAsTask token diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs index ed039bf50d2..ede74d44326 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs @@ -6,12 +6,15 @@ open System.Diagnostics open MonoDevelop.Core open Newtonsoft.Json open Microsoft.VisualStudio.FSharp.Editor.Extensions +open Microsoft.CodeAnalysis.ExternalAccess.FSharp +open Newtonsoft.Json.Converters type CompletionData = { displayText: string completionText: string category: string - icon: string + [)>] + icon: FSharpGlyph overloads: CompletionData array description: string } From e0cb943f0d52be4e88da993266fd6190c0eb89ec Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 17 Apr 2020 10:09:29 +0100 Subject: [PATCH 074/101] Scroll to last line --- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index 9e221276320..a5555aa3d3e 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -363,6 +363,17 @@ type InteractivePadController(session: InteractiveSession) as this = let inputLines = HashSet() + let scrollToLastLine() = + let textBuffer = textView.TextBuffer + let snapshot = textBuffer.CurrentSnapshot + let lineCount = snapshot.LineCount + + if lineCount > 0 then + let line = snapshot.GetLineFromLineNumber(lineCount - 1) + let snapshotSpan = new SnapshotSpan(line.Start, 0) + + textView.ViewScroller.EnsureSpanVisible(snapshotSpan); + member this.View = view member this.IsInputLine(line:int) = @@ -385,6 +396,7 @@ type InteractivePadController(session: InteractiveSession) as this = if edit.Insert(position, text) then edit.Apply() |> ignore + scrollToLastLine() member this.SetPrompt() = this.FsiOutput "\n" @@ -396,6 +408,7 @@ type InteractivePadController(session: InteractiveSession) as this = let glyphManager = InteractiveGlyphManagerService.getGlyphManager(textView) inputLines.Add(snapshot.LineCount - 1) |> ignore + scrollToLastLine() glyphManager.AddPrompt lastLine.Start.Position //(glyphManager :> ITagger).TagsChanged From 601bd697c4f72c43c501deafd2c90ecfab8996c5 Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 17 Apr 2020 10:50:31 +0100 Subject: [PATCH 075/101] Add interactive command history --- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 77 ++++++++++++++----- 1 file changed, 56 insertions(+), 21 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index a5555aa3d3e..a6fd75d1fcc 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -363,6 +363,17 @@ type InteractivePadController(session: InteractiveSession) as this = let inputLines = HashSet() + let setCaretLine text = + let snapshot = textBuffer.CurrentSnapshot + let lineCount = snapshot.LineCount + + if lineCount > 0 then + use edit = textBuffer.CreateEdit() + let line = snapshot.GetLineFromLineNumber(lineCount - 1) + + if edit.Replace(new Span(line.Start.Position, line.Length), text) then + edit.Apply() |> ignore + let scrollToLastLine() = let textBuffer = textView.TextBuffer let snapshot = textBuffer.CurrentSnapshot @@ -378,15 +389,12 @@ type InteractivePadController(session: InteractiveSession) as this = member this.IsInputLine(line:int) = let buffer = textView.TextBuffer - let snapshot = buffer.CurrentSnapshot inputLines.Contains line member this.FsiInput text = let fileName = getActiveDocumentFileName() history.Push text let buffer = textView.TextBuffer - let snapshot = buffer.CurrentSnapshot - //inputLines.Add(snapshot.LineCount - 1) |> ignore session.SendInput (text + "\n") fileName member this.FsiOutput text = @@ -401,40 +409,29 @@ type InteractivePadController(session: InteractiveSession) as this = member this.SetPrompt() = this.FsiOutput "\n" let buffer = textView.TextBuffer - //use edit = buffer.CreateEdit() let snapshot = buffer.CurrentSnapshot let lastLine = snapshot.GetLineFromLineNumber(snapshot.LineCount - 1) - //let span = new SnapshotSpan(lastLine.Start., lastLine.End) let glyphManager = InteractiveGlyphManagerService.getGlyphManager(textView) inputLines.Add(snapshot.LineCount - 1) |> ignore scrollToLastLine() glyphManager.AddPrompt lastLine.Start.Position - //(glyphManager :> ITagger).TagsChanged + member this.HistoryUp() = + history.Up() |> Option.iter setCaretLine + + member this.HistoryDown() = + history.Down() + |> function Some c -> setCaretLine c | None -> setCaretLine "" [)>] [] [)>] -//[TagType(typeof(BreakpointDisabledGlyphTag))] -//[TagType(typeof(BreakpointInvalidGlyphTag))] -//[TagType(typeof(TracepointGlyphTag))] -//[TagType(typeof(TracepointDisabledGlyphTag))] -//[TagType(typeof(TracepointInvalidGlyphTag))] -//[TextViewRole(PredefinedTextViewRoles.Debuggable)] type InteractivePromptGlyphTaggerProvider() = interface IViewTaggerProvider with - //[Import] - //public ITextDocumentFactoryService TextDocumentFactoryService { get; set; } - - //public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag member x.CreateTagger(textView, buffer) = box(InteractivePromptGlyphTagger textView) :?> _ -//module InteractiveControllerProvider = -// let getOrCreateController(textView: ITextView) = -// textView.Properties.GetOrCreateSingletonProperty(typeof, fun () -> new InteractivePadController()) - type FSharpInteractivePad() as this = inherit MonoDevelop.Ide.Gui.PadContent() @@ -768,7 +765,7 @@ type InteractivePadCompletionReturnHandler ( completionBroker:ICompletionBroker ) = interface ICommandHandler with - member x.DisplayName = "InteractivePadCompletionReturn" + member x.DisplayName = "InteractivePadKeyReturnHandler" member x.GetCommandState _args = CommandState.Available @@ -793,6 +790,44 @@ type InteractivePadCompletionReturnHandler controller.FsiOutput "\n" controller.FsiInput text true + +[] +[] +[)>] +type InteractivePadCompletionUpHandler + [] + ( completionBroker:ICompletionBroker ) = + interface ICommandHandler with + member x.DisplayName = "InteractivePadKeyUpHandler" + member x.GetCommandState _args = CommandState.Available + + member x.ExecuteCommand(args, context) = + if completionBroker.IsCompletionActive(args.TextView) then + false + else + let textView = args.TextView + let (controller: InteractivePadController) = downcast textView.Properties.[typeof] + controller.HistoryUp() + true + +[] +[] +[)>] +type InteractivePadCompletionDownHandler + [] + ( completionBroker:ICompletionBroker ) = + interface ICommandHandler with + member x.DisplayName = "InteractivePadKeyDownHandler" + member x.GetCommandState _args = CommandState.Available + + member x.ExecuteCommand(args, context) = + if completionBroker.IsCompletionActive(args.TextView) then + false + else + let textView = args.TextView + let (controller: InteractivePadController) = downcast textView.Properties.[typeof] + controller.HistoryDown() + true /// handles keypresses for F# Interactive //type FSharpFsiEditorCompletion() = // inherit TextEditorExtension() From e7b72bc02b364b34c9fcbbbc36e4f32bf4273c6c Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 17 Apr 2020 11:57:15 +0100 Subject: [PATCH 076/101] Mark readonly region --- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index a6fd75d1fcc..f5b01284cd1 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -363,27 +363,37 @@ type InteractivePadController(session: InteractiveSession) as this = let inputLines = HashSet() - let setCaretLine text = + let getLastLine() = let snapshot = textBuffer.CurrentSnapshot let lineCount = snapshot.LineCount if lineCount > 0 then + Some (snapshot.GetLineFromLineNumber(lineCount - 1)) + else + None + + let setCaretLine text = + getLastLine() |> Option.iter(fun line -> use edit = textBuffer.CreateEdit() - let line = snapshot.GetLineFromLineNumber(lineCount - 1) if edit.Replace(new Span(line.Start.Position, line.Length), text) then - edit.Apply() |> ignore + edit.Apply() |> ignore) let scrollToLastLine() = - let textBuffer = textView.TextBuffer - let snapshot = textBuffer.CurrentSnapshot - let lineCount = snapshot.LineCount - - if lineCount > 0 then - let line = snapshot.GetLineFromLineNumber(lineCount - 1) + getLastLine() |> Option.iter(fun line -> let snapshotSpan = new SnapshotSpan(line.Start, 0) + textView.ViewScroller.EnsureSpanVisible(snapshotSpan)) + + let mutable readOnlyRegion = None + + let updateReadOnlyRegion() = + getLastLine() |> Option.iter(fun line -> + use edit = textBuffer.CreateReadOnlyRegionEdit() + + readOnlyRegion |> Option.iter(fun region -> edit.RemoveReadOnlyRegion region) + readOnlyRegion <- edit.CreateReadOnlyRegion(new Span(0, line.Start.Position - 1)) |> Some - textView.ViewScroller.EnsureSpanVisible(snapshotSpan); + edit.Apply() |> ignore) member this.View = view @@ -405,6 +415,7 @@ type InteractivePadController(session: InteractiveSession) as this = if edit.Insert(position, text) then edit.Apply() |> ignore scrollToLastLine() + updateReadOnlyRegion() member this.SetPrompt() = this.FsiOutput "\n" @@ -415,6 +426,7 @@ type InteractivePadController(session: InteractiveSession) as this = inputLines.Add(snapshot.LineCount - 1) |> ignore scrollToLastLine() + updateReadOnlyRegion() glyphManager.AddPrompt lastLine.Start.Position member this.HistoryUp() = @@ -786,7 +798,7 @@ type InteractivePadCompletionReturnHandler let start = Math.Min(start, finish); let span = new Span(start, finish - start) - let text = snapshot.GetText(span).Trim() + let text = snapshot.GetText(span) controller.FsiOutput "\n" controller.FsiInput text true From cba1c75b004cc810b9ee5691acec70cc316879db Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 17 Apr 2020 12:27:35 +0100 Subject: [PATCH 077/101] Ensure that input only occurs on last line --- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index f5b01284cd1..bb9ebdacc3a 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -436,6 +436,11 @@ type InteractivePadController(session: InteractiveSession) as this = history.Down() |> function Some c -> setCaretLine c | None -> setCaretLine "" + member this.EnsureLastLine() = + getLastLine() |> Option.iter(fun line -> + if textView.Caret.Position.BufferPosition.Position < line.Start.Position then + textView.Caret.MoveTo(line.End) |> ignore) + [)>] [] [)>] @@ -753,25 +758,26 @@ type FSharpInteractivePad() as this = let file = dlg.SelectedFile //x.SendCommand ("#load @\"" + file.FullPath.ToString() + "\"") () -[] + +[] [] -//[] [)>] -[] -type InteractivePadCompletionTypeCharHandler() = +type InteractivePadCompletionTypeCharHandler + [] + ( completionBroker:ICompletionBroker ) = interface ICommandHandler with - member x.DisplayName = "InteractivePadCompletionTypeCharHandler" - member x.GetCommandState _args = - CommandState.Available + member x.DisplayName = "InteractivePadTypeCharHandler" + member x.GetCommandState _args = CommandState.Available - member x.ExecuteCommand(args, context) = + member x.ExecuteCommand(args, _context) = + let textView = args.TextView + let (controller: InteractivePadController) = downcast textView.Properties.[typeof] + controller.EnsureLastLine() false [] [] -//[] [)>] -//[] type InteractivePadCompletionReturnHandler [] ( completionBroker:ICompletionBroker ) = From 5d93b1feae7dc6862d7d80c7812cdaa8872bfe0a Mon Sep 17 00:00:00 2001 From: nosami Date: Fri, 17 Apr 2020 13:55:58 +0100 Subject: [PATCH 078/101] Fix backspace and return key handling --- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index bb9ebdacc3a..66ba164fae0 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -438,7 +438,7 @@ type InteractivePadController(session: InteractiveSession) as this = member this.EnsureLastLine() = getLastLine() |> Option.iter(fun line -> - if textView.Caret.Position.BufferPosition.Position < line.Start.Position then + if textView.Caret.Position.BufferPosition.Position <= line.Start.Position then textView.Caret.MoveTo(line.End) |> ignore) [)>] @@ -775,6 +775,31 @@ type InteractivePadCompletionTypeCharHandler controller.EnsureLastLine() false +[] +[] +[)>] +type InteractivePadCompletionBackspaceHandler + [] + ( completionBroker:ICompletionBroker ) = + + interface ICommandHandler with + member x.DisplayName = "InteractivePadKeyBackspaceHandler" + member x.GetCommandState _args = CommandState.Available + + member x.ExecuteCommand(args, _context) = + let textView = args.TextView + let snapshot = textView.TextBuffer.CurrentSnapshot + let lineCount = snapshot.LineCount + + if lineCount > 0 then + let line = snapshot.GetLineFromLineNumber(lineCount - 1) + if textView.Caret.Position.BufferPosition.Position > line.Start.Position then + false + else + true + else + true + [] [] [)>] @@ -784,8 +809,7 @@ type InteractivePadCompletionReturnHandler interface ICommandHandler with member x.DisplayName = "InteractivePadKeyReturnHandler" - member x.GetCommandState _args = - CommandState.Available + member x.GetCommandState _args = CommandState.Available member x.ExecuteCommand(args, context) = if completionBroker.IsCompletionActive(args.TextView) then @@ -798,15 +822,15 @@ type InteractivePadCompletionReturnHandler let snapshot = textBuffer.CurrentSnapshot let position = textView.Caret.Position.BufferPosition.Position let line = snapshot.GetLineFromPosition(position) - let start = line.Start.Position - let finish = line.End.Position - - let start = Math.Min(start, finish); - let span = new Span(start, finish - start) - let text = snapshot.GetText(span) - controller.FsiOutput "\n" - controller.FsiInput text + if line.Length > 0 then + let start = line.Start.Position + let finish = line.End.Position + let start = Math.Min(start, finish); + let span = new Span(start, finish - start) + let text = snapshot.GetText(span) + controller.FsiOutput "\n" + controller.FsiInput text true [] From 3fe16f14ec8925c0bff368219a77055fce0bbf62 Mon Sep 17 00:00:00 2001 From: nosami Date: Sat, 18 Apr 2020 12:00:28 +0100 Subject: [PATCH 079/101] Add interactive completion tooltips --- .../Completion/CompletionProvider.fs | 1 + .../FSharp.Editor/Completion/GlyphHelper.fs | 2 +- .../FSharp.Editor/VSMac/CompletionService.fs | 34 ++++++++++++++++--- .../FSharp.Editor/VSMac/InteractiveSession.fs | 23 ++++++++++--- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index b583ccf555b..99f72e5bc88 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -293,6 +293,7 @@ type internal FSharpCompletionProvider | _ -> return CompletionDescription.Empty } |> RoslynHelpers.StartAsyncAsTask cancellationToken + override this.GetChangeAsync(document, item, _, cancellationToken) : Task = async { use _logBlock = Logger.LogBlockMessage document.Name LogEditorFunctionId.Completion_GetChangeAsync diff --git a/vsintegration/src/FSharp.Editor/Completion/GlyphHelper.fs b/vsintegration/src/FSharp.Editor/Completion/GlyphHelper.fs index 5ba2738afb4..1784fe2e3b4 100644 --- a/vsintegration/src/FSharp.Editor/Completion/GlyphHelper.fs +++ b/vsintegration/src/FSharp.Editor/Completion/GlyphHelper.fs @@ -11,7 +11,7 @@ module GlyphHelper = // https://github.com/dotnet/roslyn/issues/26642 let imageCatalogGuid = Guid.Parse("ae27a6b0-e345-4288-96df-5eaf394ee369"); - let getImageId (glyph:Glyph) = + let getImageId (glyph:Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpGlyph) = // VS for mac cannot refer to ImageMoniker // so we need to expose ImageId instead of ImageMoniker here // and expose ImageMoniker in the EditorFeatures.wpf.dll diff --git a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs index b2d48d64d16..2526a680707 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs @@ -221,6 +221,7 @@ type internal FSharpInteractiveCompletionSource let commitChars = [|' '; '='; ','; '.'; '<'; '>'; '('; ')'; '!'; ':'; '['; ']'; '|'|].ToImmutableArray() let imageCatalogGuid = Guid.Parse("ae27a6b0-e345-4288-96df-5eaf394ee369"); + let documentationBuilder = XmlDocumentation.Provider() interface IAsyncExpandingCompletionSource with member __.GetExpandedCompletionContextAsync(session, expander, initialTrigger, applicableToSpan, token) = @@ -268,12 +269,37 @@ type internal FSharpInteractiveCompletionSource /// An object that will be passed to . See its documentation for supported types. member __.GetDescriptionAsync(session, item, token) = async { - let document = session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() - //let! sourceText = document.GetTextAsync() |> Async.AwaitTask - let provider = FSharpCompletionProvider(document.Project.Solution.Workspace, checkerProvider, projectInfoManager, assemblyContentProvider) - let! description = provider.GetDescriptionAsync2(session.TextView, item, token) |> Async.AwaitTask + System.Diagnostics.Trace.WriteLine("GetCompletionContextAsync") + let (interactiveSession: InteractiveSession) = downcast textView.Properties.[typeof] + //let snapshot = session.TextView.TextBuffer.CurrentSnapshot + //let line = snapshot.GetLineFromPosition(triggerLocation.Position) + //let start = line.Start.Position + //let finish = line.End.Position + + //let span = new Span(start, finish - start) + //let text = snapshot.GetText(span).Trim() + //session.TextView.Properties.["PotentialCommitCharacters"] <- commitChars + interactiveSession.SendTooltipRequest item.DisplayText + let! tooltip = interactiveSession.TooltipReceived |> Async.AwaitEvent + let description = + match tooltip with + | Some description -> + let documentation = List() + let collector = RoslynHelpers.CollectTaggedText documentation + // mix main description and xmldoc by using one collector + XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, collector, collector, collector, description) + CompletionDescription.Create(documentation.ToImmutableArray()) + | None -> + CompletionDescription.Empty let elements = description.TaggedParts |> buildClassifiedTextElements return ContainerElement(ContainerElementStyle.Stacked ||| ContainerElementStyle.VerticalPadding, elements |> Seq.map box) :> obj + // return + //let document = session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() + ////let! sourceText = document.GetTextAsync() |> Async.AwaitTask + //let provider = FSharpCompletionProvider(document.Project.Solution.Workspace, checkerProvider, projectInfoManager, assemblyContentProvider) + //let! description = provider.GetDescriptionAsync2(session.TextView, item, token) |> Async.AwaitTask + //let elements = description.TaggedParts |> buildClassifiedTextElements + //return ContainerElement(ContainerElementStyle.Stacked ||| ContainerElementStyle.VerticalPadding, elements |> Seq.map box) :> obj //return elements :> obj } |> RoslynHelpers.StartAsyncAsTask token diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs index ede74d44326..80ef844dd12 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs @@ -6,20 +6,35 @@ open System.Diagnostics open MonoDevelop.Core open Newtonsoft.Json open Microsoft.VisualStudio.FSharp.Editor.Extensions -open Microsoft.CodeAnalysis.ExternalAccess.FSharp open Newtonsoft.Json.Converters +open FSharp.Compiler.SourceCodeServices +open System.Runtime.Serialization.Formatters.Binary type CompletionData = { displayText: string completionText: string category: string [)>] - icon: FSharpGlyph + icon: Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpGlyph overloads: CompletionData array description: string } +module binaryDeserializer = + let deserializeFromString<'T>(base64) = + match base64 with + | "" -> + None + | _ -> + let b = Convert.FromBase64String(base64) + use stream = new MemoryStream(b) + let formatter = new BinaryFormatter() + let (o:'T) = downcast formatter.Deserialize(stream) + Some o + type InteractiveSession(pathToExe) = + let jsonSettings = JsonSerializerSettings(ReferenceLoopHandling = ReferenceLoopHandling.Ignore, TypeNameHandling = TypeNameHandling.Auto) + let (|Completion|_|) (command: string) = if command.StartsWith("completion ") then let payload = command.[11..] @@ -30,7 +45,7 @@ type InteractiveSession(pathToExe) = let (|Tooltip|_|) (command: string) = if command.StartsWith("tooltip ") then let payload = command.[8..] - Some (JsonConvert.DeserializeObject payload) + Some (binaryDeserializer.deserializeFromString(payload)) else None @@ -92,7 +107,7 @@ type InteractiveSession(pathToExe) = let completionsReceivedEvent = new Event() let imageReceivedEvent = new Event() - let tooltipReceivedEvent = new Event() + let tooltipReceivedEvent = new Event() let parameterHintReceivedEvent = new Event() do fsiProcess.OutputDataReceived From 691f9e1f64c667077299c1f2541aac28e8be66a5 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 22 Apr 2020 12:29:57 +0100 Subject: [PATCH 080/101] Add F# Interactive signature help --- .../FSharp.Editor/Completion/SignatureHelp.fs | 2 +- .../DocComments/XMLDocumentation.fs | 9 +- .../src/FSharp.Editor/FSharp.Editor.fsproj | 1 + .../src/FSharp.Editor/VSMac/InteractivePad.fs | 30 ++- .../FSharp.Editor/VSMac/InteractiveSession.fs | 8 +- .../src/FSharp.Editor/VSMac/SignatureHelp.fs | 253 ++++++++++++++++++ 6 files changed, 286 insertions(+), 17 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs diff --git a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs index 2e69221321b..5ae030b1e51 100644 --- a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs +++ b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs @@ -36,7 +36,7 @@ type internal FSharpSignatureHelpProvider static let oneColBefore (lp: LinePosition) = LinePosition(lp.Line,max 0 (lp.Character-1)) // Unit-testable core routine - static member internal ProvideMethodsAsyncAux(checker: FSharpChecker, documentationBuilder: IDocumentationBuilder, sourceText: SourceText, caretPosition: int, options: FSharpProjectOptions, triggerIsTypedChar: char option, filePath: string, textVersionHash: int) = async { + static member internal ProvideMethodsAsyncAux(checker:FSharpChecker, documentationBuilder: IDocumentationBuilder, sourceText: SourceText, caretPosition: int, options: FSharpProjectOptions, triggerIsTypedChar: char option, filePath: string, textVersionHash: int) = async { let! parseResults, checkFileAnswer = checker.ParseAndCheckFileInProject(filePath, textVersionHash, sourceText.ToFSharpSourceText(), options, userOpName = userOpName) match checkFileAnswer with | FSharpCheckFileAnswer.Aborted -> return None diff --git a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs index 57260553620..afe0fb03760 100644 --- a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs +++ b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs @@ -301,11 +301,14 @@ module internal XmlDocumentation = type FSharpXmlDocumentationProvider(assemblyPath) = inherit Microsoft.CodeAnalysis.XmlDocumentationProvider() let xmlPath = Path.ChangeExtension(assemblyPath, ".xml") - + let xmlExists = File.Exists xmlPath member x.XmlPath = xmlPath member x.GetDocumentation documentationCommentId = - let xml = base.GetDocumentationForSymbol(documentationCommentId, Globalization.CultureInfo.CurrentCulture, CancellationToken.None) - xml + match xmlExists with + | true -> + let xml = base.GetDocumentationForSymbol(documentationCommentId, Globalization.CultureInfo.CurrentCulture, CancellationToken.None) + xml + | false -> "" override x.GetSourceStream(_cancellationToken) = new FileStream(xmlPath, FileMode.Open, FileAccess.Read) :> Stream diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 1537f0e7b8e..9b165720c7b 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -263,6 +263,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index 66ba164fae0..e01ef392f8b 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -201,6 +201,7 @@ type ShellHistory() = member x.Up() = match nextUp with | -1 -> None + | index when index >= history.Count -> None | index -> nextDown <- nextUp nextUp <- nextUp - 1 @@ -396,6 +397,7 @@ type InteractivePadController(session: InteractiveSession) as this = edit.Apply() |> ignore) member this.View = view + member this.Session = session member this.IsInputLine(line:int) = let buffer = textView.TextBuffer @@ -764,12 +766,15 @@ type FSharpInteractivePad() as this = [)>] type InteractivePadCompletionTypeCharHandler [] - ( completionBroker:ICompletionBroker ) = + ( completionBroker:ICompletionBroker, + signatureHelpBroker:ISignatureHelpBroker ) = interface ICommandHandler with member x.DisplayName = "InteractivePadTypeCharHandler" member x.GetCommandState _args = CommandState.Available member x.ExecuteCommand(args, _context) = + if args.TypedChar <> '(' && args.TypedChar <> ',' && args.TypedChar <> ' ' then + signatureHelpBroker.DismissAllSessions(args.TextView) let textView = args.TextView let (controller: InteractivePadController) = downcast textView.Properties.[typeof] controller.EnsureLastLine() @@ -805,17 +810,18 @@ type InteractivePadCompletionBackspaceHandler [)>] type InteractivePadCompletionReturnHandler [] - ( completionBroker:ICompletionBroker ) = - + ( completionBroker:ICompletionBroker, + signatureHelpBroker:ISignatureHelpBroker ) = interface ICommandHandler with member x.DisplayName = "InteractivePadKeyReturnHandler" member x.GetCommandState _args = CommandState.Available member x.ExecuteCommand(args, context) = - if completionBroker.IsCompletionActive(args.TextView) then + let textView = args.TextView + signatureHelpBroker.DismissAllSessions(textView) + if completionBroker.IsCompletionActive(textView) then false else - let textView = args.TextView let (controller: InteractivePadController) = downcast textView.Properties.[typeof] let textBuffer = textView.TextBuffer @@ -838,13 +844,16 @@ type InteractivePadCompletionReturnHandler [)>] type InteractivePadCompletionUpHandler [] - ( completionBroker:ICompletionBroker ) = + ( completionBroker:ICompletionBroker, + signatureHelpBroker:ISignatureHelpBroker ) = interface ICommandHandler with member x.DisplayName = "InteractivePadKeyUpHandler" member x.GetCommandState _args = CommandState.Available member x.ExecuteCommand(args, context) = - if completionBroker.IsCompletionActive(args.TextView) then + if signatureHelpBroker.IsSignatureHelpActive(args.TextView) then + false + else if completionBroker.IsCompletionActive(args.TextView) then false else let textView = args.TextView @@ -857,13 +866,16 @@ type InteractivePadCompletionUpHandler [)>] type InteractivePadCompletionDownHandler [] - ( completionBroker:ICompletionBroker ) = + ( completionBroker:ICompletionBroker, + signatureHelpBroker:ISignatureHelpBroker ) = interface ICommandHandler with member x.DisplayName = "InteractivePadKeyDownHandler" member x.GetCommandState _args = CommandState.Available member x.ExecuteCommand(args, context) = - if completionBroker.IsCompletionActive(args.TextView) then + if signatureHelpBroker.IsSignatureHelpActive(args.TextView) then + false + else if completionBroker.IsCompletionActive(args.TextView) then false else let textView = args.TextView diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs index 80ef844dd12..d3ee4dea6e3 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs @@ -3,12 +3,12 @@ open System open System.IO open System.Diagnostics +open System.Runtime.Serialization.Formatters.Binary open MonoDevelop.Core open Newtonsoft.Json open Microsoft.VisualStudio.FSharp.Editor.Extensions open Newtonsoft.Json.Converters open FSharp.Compiler.SourceCodeServices -open System.Runtime.Serialization.Formatters.Binary type CompletionData = { displayText: string @@ -45,14 +45,14 @@ type InteractiveSession(pathToExe) = let (|Tooltip|_|) (command: string) = if command.StartsWith("tooltip ") then let payload = command.[8..] - Some (binaryDeserializer.deserializeFromString(payload)) + Some (binaryDeserializer.deserializeFromString payload) else None let (|ParameterHints|_|) (command: string) = if command.StartsWith("parameter-hints ") then let payload = command.[16..] - Some (JsonConvert.DeserializeObject payload) + Some (binaryDeserializer.deserializeFromString<(FSharpNoteworthyParamInfoLocations * FSharpMethodGroup)> payload) else None @@ -108,7 +108,7 @@ type InteractiveSession(pathToExe) = let completionsReceivedEvent = new Event() let imageReceivedEvent = new Event() let tooltipReceivedEvent = new Event() - let parameterHintReceivedEvent = new Event() + let parameterHintReceivedEvent = new Event<(FSharpNoteworthyParamInfoLocations * FSharpMethodGroup) option>() do fsiProcess.OutputDataReceived |> Event.filter (fun de -> de.Data <> null) diff --git a/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs new file mode 100644 index 00000000000..479ef9dc4f6 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs @@ -0,0 +1,253 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.VisualStudio.FSharp.Editor + +open System +open System.Composition +open System.Collections.Generic + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.SignatureHelp +open Microsoft.CodeAnalysis.Text +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.SignatureHelp + +open Microsoft.VisualStudio.Text +////open Microsoft.VisualStudio.Shell +//open Microsoft.VisualStudio.Shell.Interop + +open FSharp.Compiler.Layout +open FSharp.Compiler.Range +open FSharp.Compiler.SourceCodeServices +open MonoDevelop.FSharp + +[] +[)>] +type internal FSharpInteractiveSignatureHelpProvider + [] + ( + //serviceProvider: SVsServiceProvider, + checkerProvider: FSharpCheckerProvider, + projectInfoManager: FSharpProjectOptionsManager + ) = + + static let userOpName = "SignatureHelpProvider" + let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder((*serviceProvider.XMLMemberIndexService*)) + + static let oneColAfter (lp: LinePosition) = LinePosition(lp.Line,lp.Character+1) + static let oneColBefore (lp: LinePosition) = LinePosition(lp.Line,max 0 (lp.Character-1)) + + // Unit-testable core routine + static member internal ProvideMethodsAsyncAux(nwpl:FSharpNoteworthyParamInfoLocations, methodGroup:FSharpMethodGroup, documentationBuilder: IDocumentationBuilder, sourceText: SourceText, caretPosition: int, triggerIsTypedChar: char option) = async { + ////let (interactiveSession: InteractiveSession) = downcast textView.Properties.[typeof] + + //let! parseResults, checkFileAnswer = checker.ParseAndCheckFileInProject(filePath, textVersionHash, sourceText.ToFSharpSourceText(), options, userOpName = userOpName) + //match checkFileAnswer with + //| FSharpCheckFileAnswer.Aborted -> return None + //| FSharpCheckFileAnswer.Succeeded(checkFileResults) -> + + let textLines = sourceText.Lines + let caretLinePos = textLines.GetLinePosition(caretPosition) + let caretLineColumn = caretLinePos.Character + + //// Get the parameter locations + //let paramLocations = parseResults.FindNoteworthyParamInfoLocations(Pos.fromZ 0 caretLineColumn) + + //match paramLocations with + //| None -> return None // no locations = no help + //| Some nwpl -> + //let names = nwpl.LongId + //let lidEnd = nwpl.LongIdEndLocation + + // Get the methods + //let! methodGroup = checkFileResults.GetMethods(lidEnd.Line, lidEnd.Column, "", Some names) + + let methods = methodGroup.Methods + + if (methods.Length = 0 || methodGroup.MethodName.EndsWith("> )")) then return None else + + let isStaticArgTip = + let parenLine, parenCol = Pos.toZ nwpl.OpenParenLocation + assert (parenLine < textLines.Count) + let parenLineText = textLines.[parenLine].ToString() + parenCol < parenLineText.Length && parenLineText.[parenCol] = '<' + + let filteredMethods = + [| for m in methods do + if (isStaticArgTip && m.StaticParameters.Length > 0) || + (not isStaticArgTip && m.HasParameters) then // need to distinguish TP<...>(...) angle brackets tip from parens tip + yield m |] + + if filteredMethods.Length = 0 then return None else + + let posToLinePosition pos = + let (l,c) = Pos.toZ pos + // FSROSLYNTODO: FCS gives back line counts that are too large. Really, this shouldn't happen + let result =LinePosition(l,c) + let lastPosInDocument = textLines.GetLinePosition(textLines.[textLines.Count-1].End) + if lastPosInDocument.CompareTo(result) > 0 then result else lastPosInDocument + + // Compute the start position + let startPos = nwpl.LongIdStartLocation |> posToLinePosition + + // Compute the end position + let endPos = + let last = nwpl.TupleEndLocations.[nwpl.TupleEndLocations.Length-1] |> posToLinePosition + (if nwpl.IsThereACloseParen then oneColBefore last else last) + + assert (startPos.CompareTo(endPos) <= 0) + + // Compute the applicable span between the parentheses + let applicableSpan = + textLines.GetTextSpan(LinePositionSpan(startPos, endPos)) + + let startOfArgs = nwpl.OpenParenLocation |> posToLinePosition |> oneColAfter + + let tupleEnds = + [| yield startOfArgs + for i in 0..nwpl.TupleEndLocations.Length-2 do + yield nwpl.TupleEndLocations.[i] |> posToLinePosition + yield endPos |] + + // If we are pressing "(" or "<" or ",", then only pop up the info if this is one of the actual, real detected positions in the detected promptable call + // + // For example the last "(" in + // List.map (fun a -> ( + // should not result in a prompt. + // + // Likewise the last "," in + // Console.WriteLine( [(1, + // should not result in a prompt, whereas this one will: + // Console.WriteLine( [(1,2)], + + //match triggerIsTypedChar with + //| Some ('<' | '(' | ',') when not (tupleEnds |> Array.exists (fun lp -> lp.Character = caretLineColumn)) -> + // return None // comma or paren at wrong location = remove help display + //| _ -> + + // Compute the argument index by working out where the caret is between the various commas. + let argumentIndex = + let computedTextSpans = + tupleEnds + |> Array.pairwise + |> Array.map (fun (lp1, lp2) -> textLines.GetTextSpan(LinePositionSpan(lp1, lp2))) + + match (computedTextSpans|> Array.tryFindIndex (fun t -> t.Contains(caretPosition))) with + | None -> + // Because 'TextSpan.Contains' only succeeds if 'TextSpan.Start <= caretPosition < TextSpan.End' is true, + // we need to check if the caret is at the very last position in the TextSpan. + // + // We default to 0, which is the first argument, if the caret position was nowhere to be found. + if computedTextSpans.[computedTextSpans.Length-1].End = caretPosition then + computedTextSpans.Length-1 + else 0 + | Some n -> n + + // Compute the overall argument count + let argumentCount = + match nwpl.TupleEndLocations.Length with + | 1 when caretLinePos.Character = startOfArgs.Character -> 0 // count "WriteLine(" as zero arguments + | n -> n + + // Compute the current argument name, if any + let argumentName = + if argumentIndex < nwpl.NamedParamNames.Length then + nwpl.NamedParamNames.[argumentIndex] + else + None // not a named argument + + // Prepare the results + let results = ResizeArray() + + for method in methods do + // Create the documentation. Note, do this on the background thread, since doing it in the documentationBuild fails to build the XML index + let mainDescription = ResizeArray() + let documentation = ResizeArray() + XmlDocumentation.BuildMethodOverloadTipText(documentationBuilder, RoslynHelpers.CollectTaggedText mainDescription, RoslynHelpers.CollectTaggedText documentation, method.StructuredDescription, false) + + let parameters = + let parameters = if isStaticArgTip then method.StaticParameters else method.Parameters + [| for p in parameters do + let doc = List() + // FSROSLYNTODO: compute the proper help text for parameters, c.f. AppendParameter in XmlDocumentation.fs + XmlDocumentation.BuildMethodParamText(documentationBuilder, RoslynHelpers.CollectTaggedText doc, method.XmlDoc, p.ParameterName) + let parts = List() + renderL (taggedTextListR (RoslynHelpers.CollectTaggedText parts)) p.StructuredDisplay |> ignore + yield (p.ParameterName, p.IsOptional, p.CanonicalTypeTextForSorting, doc, parts) + |] + + let prefixParts = + [| TaggedText(TextTags.Method, methodGroup.MethodName); + TaggedText(TextTags.Punctuation, (if isStaticArgTip then "<" else "(")) |] + let separatorParts = [| TaggedText(TextTags.Punctuation, ","); TaggedText(TextTags.Space, " ") |] + let suffixParts = [| TaggedText(TextTags.Punctuation, (if isStaticArgTip then ">" else ")")) |] + + let completionItem = (method.HasParamArrayArg, documentation, prefixParts, separatorParts, suffixParts, parameters, mainDescription) + // FSROSLYNTODO: Do we need a cache like for completion? + //declarationItemsCache.Remove(completionItem.DisplayText) |> ignore // clear out stale entries if they exist + //declarationItemsCache.Add(completionItem.DisplayText, declarationItem) + results.Add(completionItem) + + + let items = (results.ToArray(),applicableSpan,argumentIndex,argumentCount,argumentName) + return Some items + } + + interface IFSharpInteractiveSignatureHelpProvider with + //member this.IsTriggerCharacter(c) = c ='(' || c = '<' || c = ',' + //member this.IsRetriggerCharacter(c) = c = ')' || c = '>' || c = '=' + + member this.GetItemsAsync(document, position, triggerInfo, cancellationToken) = + asyncMaybe { + try + let! fsi = FSharpInteractivePad.Fsi + let! controller = fsi.Controller + //let (interactiveSession: InteractiveSession) = downcast controller.View.Properties.[typeof] + + //if FSharpInteractivePad.Fsi.Value.Controller.Value.IsInputLine(line) then + + //let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + + let! sourceText = document.GetTextAsync(cancellationToken) + let line = sourceText.Lines.GetLineFromPosition(position) + let column = position - line.Start + let snapshot = sourceText.FindCorrespondingEditorTextSnapshot() + let lineText = snapshot.GetText(Span(line.Start, line.End - line.Start)) + //let fssourceText = SourceText.From(lineText).ToFSharpSourceText() + MonoDevelop.Core.LoggingService.LogDebug("parameter-hints " + column.ToString() + " " + lineText) + controller.Session.SendParameterHintRequest lineText column + + let! paramInfo, methodGroups = controller.Session.ParameterHintReceived |> Async.AwaitEvent + //let! textVersion = document.GetTextVersionAsync(cancellationToken) + ////let! parseResult, parsedInput, checkResults = checkerProvider.Checker.ParseAndCheckDocument(document, projectOptions, lineText) + //let! projectOptions, errors = checkerProvider.Checker.GetProjectOptionsFromScript(document.FilePath, fssourceText) |> liftAsync + //let parsingOptions, errors = checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions) + //let! parseResult = checkerProvider.Checker.ParseFileNoCache(document.FilePath, fssourceText, parsingOptions) |> liftAsync + //let ino = parseResult.FindNoteworthyParamInfoLocations(Pos.fromZ 0 column) + //printfn "%A" ino + let triggerTypedChar = + if triggerInfo.TriggerCharacter.HasValue && triggerInfo.TriggerReason = FSharpSignatureHelpTriggerReason.TypeCharCommand then + Some triggerInfo.TriggerCharacter.Value + else None + + let! (results,applicableSpan,argumentIndex,argumentCount,argumentName) = + FSharpInteractiveSignatureHelpProvider.ProvideMethodsAsyncAux(paramInfo, methodGroups, documentationBuilder, sourceText, column, triggerTypedChar) + let items = + results + |> Array.map (fun (hasParamArrayArg, doc, prefixParts, separatorParts, suffixParts, parameters, descriptionParts) -> + let parameters = parameters + |> Array.map (fun (paramName, isOptional, _typeText, paramDoc, displayParts) -> + FSharpSignatureHelpParameter(paramName,isOptional,documentationFactory=(fun _ -> paramDoc :> seq<_>),displayParts=displayParts)) + FSharpSignatureHelpItem(isVariadic=hasParamArrayArg, documentationFactory=(fun _ -> doc :> seq<_>),prefixParts=prefixParts,separatorParts=separatorParts,suffixParts=suffixParts,parameters=parameters,descriptionParts=descriptionParts)) + + // The text span that comes back from FCS always has line number 1. We need to map this back to the + // actual line number in the editor + let offset = position - column + let applicableAdjustedSpan = + new TextSpan(applicableSpan.Start + offset, applicableSpan.End - applicableSpan.Start - 1) + return FSharpSignatureHelpItems(items,applicableAdjustedSpan,argumentIndex,argumentCount,Option.toObj argumentName) + with ex -> + Assert.Exception(ex) + return! None + } + |> Async.map Option.toObj + |> RoslynHelpers.StartAsyncAsTask cancellationToken From 0f0671b9e5b0989affc1cdb7de4256d14957da42 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 22 Apr 2020 15:34:00 +0100 Subject: [PATCH 081/101] Re-enable clear and reset buttons --- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index e01ef392f8b..fc8ebeb874c 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -419,6 +419,10 @@ type InteractivePadController(session: InteractiveSession) as this = scrollToLastLine() updateReadOnlyRegion() + member this.Clear() = + use edit = textView.TextBuffer.CreateEdit() + edit.Delete(0, textView.TextBuffer.CurrentSnapshot.Length) |> ignore + member this.SetPrompt() = this.FsiOutput "\n" let buffer = textView.TextBuffer @@ -540,7 +544,7 @@ type FSharpInteractivePad() as this = LoggingService.LogDebug ("Interactive: process stopped") (*this.FsiOutput "\nSession termination detected. Press Enter to restart." *))|> ignore elif killIntent = Restart then - Runtime.RunInMainThread (fun () -> ()(*editor.Text <- ""*)) |> ignore + Runtime.RunInMainThread (fun () -> controller.Clear()) |> ignore killIntent <- NoIntent) ses.StartReceiving() @@ -559,8 +563,8 @@ type FSharpInteractivePad() as this = let resetFsi intent = if promptReceived then killIntent <- intent - //session |> Option.iter (fun (ses: InteractiveSession) -> ses.Kill()) - //if intent = Restart then session <- setupSession() + session |> Option.iter (fun (ses: InteractiveSession) -> ses.Kill()) + if intent = Restart then session <- setupSession() let history = ShellHistory() //new() = @@ -605,13 +609,13 @@ type FSharpInteractivePad() as this = // history.Push command // ses.SendInput (command + "\n") fileName) - //member x.SendCommand command = - // let fileName = getActiveDocumentFileName() + member x.SendCommand command = + let fileName = getActiveDocumentFileName() - // input.Add command - // session - // |> Option.iter(fun ses -> - // ses.SendInput (command + ";;") fileName) + input.Add command + session + |> Option.iter(fun ses -> + ses.SendInput (command + ";;") fileName) //member x.RequestCompletions lineStr column = // session @@ -671,9 +675,8 @@ type FSharpInteractivePad() as this = member x.SendSelection() = if x.IsSelectionNonEmpty then let textView = IdeApp.Workbench.ActiveDocument.GetContent() - () - //for span in textView.Selection.VirtualSelectedSpans do - // x.SendCommand (span.GetText()) + for span in textView.Selection.VirtualSelectedSpans do + x.SendCommand (span.GetText()) else //if nothing is selected send the whole line x.SendLine() @@ -684,13 +687,11 @@ type FSharpInteractivePad() as this = let view = IdeApp.Workbench.ActiveDocument.GetContent(); let line = view.Caret.Position.BufferPosition.GetContainingLine(); let text = line.GetText() - //x.SendCommand text - () + x.SendCommand text member x.SendFile() = let text = IdeApp.Workbench.ActiveDocument.TextBuffer.CurrentSnapshot.GetText() - //x.SendCommand text - () + x.SendCommand text member x.IsSelectionNonEmpty = if isNull IdeApp.Workbench.ActiveDocument || @@ -728,7 +729,7 @@ type FSharpInteractivePad() as this = addButton ("gtk-save", (fun _ -> x.Save()), GettextCatalog.GetString ("Save as script")) addButton ("gtk-open", (fun _ -> x.OpenScript()), GettextCatalog.GetString ("Open")) - //addButton ("gtk-clear", (fun _ -> editor.Text <- ""), GettextCatalog.GetString ("Clear")) + addButton ("gtk-clear", (fun _ -> x.ClearFsi()), GettextCatalog.GetString ("Clear")) addButton ("gtk-refresh", (fun _ -> x.RestartFsi()), GettextCatalog.GetString ("Reset")) toolbar.ShowAll() session <- setupSession() @@ -736,7 +737,7 @@ type FSharpInteractivePad() as this = member x.RestartFsi() = resetFsi Restart - //member x.ClearFsi() = editor.Text <- "" + member x.ClearFsi() = x.Controller |> Option.iter(fun c -> c.Clear()) member x.Save() = let dlg = new MonoDevelop.Ide.Gui.Dialogs.OpenFileDialog(GettextCatalog.GetString ("Save as .fsx"), MonoDevelop.Components.FileChooserAction.Save) @@ -758,8 +759,7 @@ type FSharpInteractivePad() as this = dlg.AddFilter (GettextCatalog.GetString ("F# script files"), [|".fs"; "*.fsi"; "*.fsx"; "*.fsscript"; "*.ml"; "*.mli" |]) |> ignore if dlg.Run () then let file = dlg.SelectedFile - //x.SendCommand ("#load @\"" + file.FullPath.ToString() + "\"") - () + x.SendCommand ("#load @\"" + file.FullPath.ToString() + "\"") [] [] @@ -1030,8 +1030,8 @@ type SendReferences() = type RestartFsi() = inherit InteractiveCommand(fun fsi -> fsi.RestartFsi()) -//type ClearFsi() = -// inherit InteractiveCommand(fun fsi -> fsi.ClearFsi()) +type ClearFsi() = + inherit InteractiveCommand(fun fsi -> fsi.ClearFsi()) //open System.ComponentModel.Composition //open Microsoft.VisualStudio.Text.Editor From 1d5fb79c28653e68db7c0bbb39f9ee4192caf8fd Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 27 Apr 2020 11:22:55 +0100 Subject: [PATCH 082/101] Make restart work --- .../src/FSharp.Editor/FSharp.addin.xml | 83 ++++ .../src/FSharp.Editor/VSMac/InteractivePad.fs | 453 ++---------------- .../FSharp.Editor/VSMac/InteractiveSession.fs | 127 ++--- .../VSMac/InteractiveWorkspace.fs | 19 +- 4 files changed, 187 insertions(+), 495 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index 36af081700d..69ae8a2a1e5 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -59,4 +59,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index fc8ebeb874c..0902e8eae81 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -26,50 +26,32 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System -open System.IO -open System.Threading.Tasks open System.Collections.Generic -open System.Collections.Immutable +open System.ComponentModel.Composition +open System.IO + +open FSharp.Editor open Gdk +open Gtk + +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +open Microsoft.VisualStudio.Commanding +open Microsoft.VisualStudio.Core.Imaging +open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.Language.Intellisense +open Microsoft.VisualStudio.Text +open Microsoft.VisualStudio.Text.Editor +open Microsoft.VisualStudio.Text.Editor.Commanding.Commands +open Microsoft.VisualStudio.Text.Tagging open MonoDevelop.Components -open MonoDevelop.Components.Docking open MonoDevelop.Components.Commands +open MonoDevelop.Components.Docking open MonoDevelop.Core open MonoDevelop.Core.Execution open MonoDevelop.FSharp open MonoDevelop.Ide -open MonoDevelop.Ide.CodeCompletion -open MonoDevelop.Ide.Editor -open MonoDevelop.Ide.Editor.Extension -open MonoDevelop.Ide.Gui.Content -open MonoDevelop.Ide.TypeSystem -open MonoDevelop.Projects -open Microsoft.VisualStudio.Text.Editor open MonoDevelop.Ide.Composition -open Microsoft.VisualStudio.Text -open Gtk -open Microsoft.VisualStudio.Text.Classification -open CoreGraphics -open Microsoft.VisualStudio.Core.Imaging -open Microsoft.VisualStudio.Text.Tagging -open System.ComponentModel.Composition -open Microsoft.VisualStudio.Imaging -open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion -open Microsoft.VisualStudio.Text -open Microsoft.VisualStudio.Commanding -open Microsoft.VisualStudio.Text.Editor -open Microsoft.VisualStudio.Text.Editor.Commanding.Commands -open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion -open Microsoft.VisualStudio.Language.Intellisense -open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.Text -open Microsoft.VisualStudio.FSharp.Editor -open Microsoft.VisualStudio.Text -open Microsoft.VisualStudio.Text.Editor -open Microsoft.VisualStudio.Threading -open FSharp.Editor -open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor [] module ColorHelpers = let strToColor s = @@ -94,100 +76,6 @@ type KillIntent = | Kill | NoIntent // Unexpected kill, or from #q/#quit, so we prompt -//type ImageRendererMarker(line, image:Xwt.Drawing.Image) = -// inherit TextLineMarker() -// static let tag = obj() -// override x.Draw(editor, cr, metrics) = -// cr.DrawImage(editor, image, 30.0, metrics.LineYRenderStartPosition) - -// interface ITextLineMarker with -// member x.Line with get() = line -// member x.IsVisible with get() = true and set(_value) = () -// member x.Tag with get() = tag and set(_value) = () - -// interface IExtendingTextLineMarker with -// member x.GetLineHeight editor = editor.LineHeight + image.Height -// member x.Draw(_editor, _g, _lineNr, _lineArea) = () -// member x.IsSpaceAbove with get() = false - -//type FsiDocumentContext() = -// inherit DocumentContext() -// static let name = "__FSI__.fs" -// let pd = new FSharpParsedDocument(name, None, None) :> ParsedDocument -// let project = Services.ProjectService.CreateDotNetProject ("F#") - -// let mutable completionWidget:ICompletionWidget = null -// let mutable editor:TextEditor = null - -// let contextChanged = DelegateEvent<_>() -// let mutable workingFolder: string option = None -// do -// project.FileName <- FilePath name - -// override x.ParsedDocument = pd -// override x.AttachToProject(_) = () -// override x.ReparseDocument() = () -// override x.GetOptionSet() = IdeApp.TypeSystemService.Workspace.Options -// override x.Project = project :> Project -// override x.Name = name -// override x.AnalysisDocument with get() = null -// override x.UpdateParseDocument() = Task.FromResult pd -// static member DocumentName = name -// member x.CompletionWidget -// with set (value) = -// completionWidget <- value -// completionWidget.CompletionContextChanged.Add -// (fun _args -> let completion = editor.GetContent() -// ParameterInformationWindowManager.HideWindow(completion, value)) -// member x.Editor with set (value) = editor <- value -// member x.WorkingFolder -// with get() = workingFolder -// and set(folder) = workingFolder <- folder -// interface ICompletionWidget with -// member x.CaretOffset -// with get() = completionWidget.CaretOffset -// and set(offset) = completionWidget.CaretOffset <- offset -// member x.TextLength = editor.Length -// member x.SelectedLength = completionWidget.SelectedLength -// member x.GetText(startOffset, endOffset) = -// completionWidget.GetText(startOffset, endOffset) -// member x.GetChar offset = editor.GetCharAt offset -// member x.Replace(offset, count, text) = -// completionWidget.Replace(offset, count, text) -// member x.GtkStyle = completionWidget.GtkStyle - -// member x.ZoomLevel = completionWidget.ZoomLevel -// member x.CreateCodeCompletionContext triggerOffset = -// completionWidget.CreateCodeCompletionContext triggerOffset -// member x.CurrentCodeCompletionContext -// with get() = completionWidget.CurrentCodeCompletionContext - -// member x.GetCompletionText ctx = completionWidget.GetCompletionText ctx - -// member x.SetCompletionText (ctx, partialWord, completeWord) = -// completionWidget.SetCompletionText (ctx, partialWord, completeWord) -// member x.SetCompletionText (ctx, partialWord, completeWord, completeWordOffset) = -// completionWidget.SetCompletionText (ctx, partialWord, completeWord, completeWordOffset) -// [] -// member x.CompletionContextChanged = contextChanged.Publish - -//type FsiPrompt(icon: Xwt.Drawing.Image) = -// inherit MarginMarker() - -// override x.CanDrawForeground margin = -// margin :? IconMargin - -// override x.DrawForeground (editor, cairoContext, metrics) = -// let size = metrics.Margin.Width -// let borderLineWidth = cairoContext.LineWidth - -// let x = Math.Floor (metrics.Margin.XOffset - borderLineWidth / 2.0) -// let y = Math.Floor (metrics.Y + (metrics.Height - size) / 2.0) - -// let deltaX = size / 2.0 - icon.Width / 2.0 + 0.5 -// let deltaY = size / 2.0 - icon.Height / 2.0 + 0.5 -// cairoContext.DrawImage (editor, icon, Math.Round (x + deltaX), Math.Round (y + deltaY)); - type ShellHistory() = let history = ResizeArray() let mutable nextUp = 0 @@ -218,8 +106,6 @@ type ShellHistory() = else Some history.[nextDown] - - type InteractivePromptGlyphTag() = interface IGlyphTag type InteractiveGlyphFactory(imageId:ImageId, imageService:IImageService) = @@ -241,7 +127,6 @@ type InteractiveGlyphFactory(imageId:ImageId, imageService:IImageService) = [] [] [)>] -//[] type InteractiveGlyphFactoryProvider() as this = [] member val ImageService:IImageService = null with get, set @@ -256,15 +141,10 @@ type InteractivePromptGlyphTagger(textView: ITextView) as this = let tagsChanged = Event<_,_>() let promptSpans = HashSet<_>() - let promptsChanged = Event<_>() do - // glyphManager.PromptsChanged.Add(fun (args) -> - // tagsChanged.Trigger(this, args))// (this :> ITagger).Ta textView.Properties.[typeof] <- this - //member x.Controller = textView.Properties.[typeof] :?> InteractivePadController - member x.AddPrompt(pos:int) = if promptSpans.Add(pos) then tagsChanged.Trigger(this, SnapshotSpanEventArgs(SnapshotSpan(textView.TextSnapshot, pos, 1))) @@ -273,14 +153,6 @@ type InteractivePromptGlyphTagger(textView: ITextView) as this = [] member this.TagsChanged = tagsChanged.Publish - /// - /// Occurs when tags are added to or removed from the provider. - /// - //event EventHandler TagsChanged; - //member this.add_TagsChanged(handler) = tagsChanged.Publish - - //member this.remove_TagsChanged(handler) = ()// tagsChanged.Publish.RemoveHandler(handler) - //public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) member x.GetTags(spans) = seq { for span in spans do @@ -288,18 +160,6 @@ type InteractivePromptGlyphTagger(textView: ITextView) as this = yield TagSpan(span, InteractivePromptGlyphTag()) } -//type InteractiveGlyphManager(textView:ITextView) = -// let promptSpans = HashSet<_>() -// let promptsChanged = new Event<_>() - -// member x.PromptsChanged = promptsChanged.Publish - -// member x.PromptSpans = promptSpans - -// member x.AddPrompt(pos:int) = -// if promptSpans.Add(pos) then -// promptsChanged.Trigger(new SnapshotSpanEventArgs(new SnapshotSpan(textView.TextSnapshot, pos, 1))) - module InteractiveGlyphManagerService = let getGlyphManager(textView: ITextView) = textView.Properties.GetOrCreateSingletonProperty(typeof, fun () -> InteractivePromptGlyphTagger textView) @@ -309,25 +169,17 @@ module InteractiveGlyphManagerService = [] type InteractivePadController(session: InteractiveSession) as this = let mutable view = null - //let mutable textView = null let contentTypeRegistry = CompositionManager.Instance.GetExportedValue() let textBufferFactory = CompositionManager.Instance.GetExportedValue() let factory = CompositionManager.Instance.GetExportedValue() let contentType = contentTypeRegistry.GetContentType(FSharpContentTypeNames.FSharpInteractiveContentType) - //let editorFormatMapService = CompositionManager.Instance.GetExportedValue() - - //let appearanceCategory = Guid.NewGuid().ToString() - //let editorFormat = editorFormatMapService.GetEditorFormatMap(appearanceCategory) - //let resourceDictionary = editorFormat.GetProperties("Plain Text") let roles = factory.CreateTextViewRoleSet(PredefinedTextViewRoles.Editable, PredefinedTextViewRoles.Interactive, PredefinedTextViewRoles.Document) let textBuffer = textBufferFactory.CreateTextBuffer("", contentType) let textView = factory.CreateTextView(textBuffer, roles) let workspace = new InteractiveWorkspace() - //let (workspace: MiscellaneousFilesWorkspace) = downcast IdeApp.TypeSystemService.GetWorkspaceInternal(null) let history = ShellHistory() - //textView.Background <- CGColor.CreateSrgb(nfloat 0.0, nfloat 0.0, nfloat 0.0, nfloat 0.0) do //resourceDictionary.[ClassificationFormatDefinition.TypefaceId] <- TextField.Font //resourceDictionary.[ClassificationFormatDefinition.FontRenderingSizeId] <- 20 @@ -336,7 +188,6 @@ type InteractivePadController(session: InteractiveSession) as this = //editorFormat.SetProperties("Plain Text", resourceDictionary) textView.Options.SetOptionValue(DefaultTextViewOptions.UseVisibleWhitespaceId, false) - //textView.Options.SetOptionValue(DefaultCocoaViewOptions.AppearanceCategory, appearanceCategory) textView.Options.SetOptionValue(DefaultTextViewHostOptions.ChangeTrackingId, false) textView.Options.SetOptionValue(DefaultTextViewHostOptions.LineNumberMarginId, false) textView.Options.SetOptionValue(DefaultTextViewHostOptions.OutliningMarginId, false) @@ -344,12 +195,8 @@ type InteractivePadController(session: InteractiveSession) as this = textView.VisualElement.TranslatesAutoresizingMaskIntoConstraints <- false textView.Properties.[typeof] <- this textView.Properties.[typeof] <- session - //textView.Properties.[typeof] <- this let host = factory.CreateTextViewHost(textView, true) view <- host.HostControl - // Add the view to a workspace so that Roslyn can fetch LanguageServices - // Note: this fake file name must end with .fs, not .fsx so that we don't get the MiscellaneousFilesWorkspace - //workspace.OnDocumentOpened("interactive.fsx", textBuffer) workspace.CreateDocument(textBuffer) let getActiveDocumentFileName () = @@ -357,7 +204,6 @@ type InteractivePadController(session: InteractiveSession) as this = let docFileName = IdeApp.Workbench.ActiveDocument.FileName.ToString() if docFileName <> null then let directoryName = Path.GetDirectoryName docFileName - //ctx.WorkingFolder <- Some directoryName Some docFileName else None else None @@ -420,8 +266,15 @@ type InteractivePadController(session: InteractiveSession) as this = updateReadOnlyRegion() member this.Clear() = + inputLines.Clear() + use readOnlyEdit = textBuffer.CreateReadOnlyRegionEdit() + readOnlyRegion |> Option.iter(fun region -> readOnlyEdit.RemoveReadOnlyRegion region) + readOnlyRegion <- None + readOnlyEdit.Apply() |> ignore + use edit = textView.TextBuffer.CreateEdit() edit.Delete(0, textView.TextBuffer.CurrentSnapshot.Length) |> ignore + edit.Apply() |> ignore member this.SetPrompt() = this.FsiOutput "\n" @@ -457,21 +310,8 @@ type InteractivePromptGlyphTaggerProvider() = type FSharpInteractivePad() as this = inherit MonoDevelop.Ide.Gui.PadContent() - - //let ctx = editor.DocumentContext :?> FsiDocumentContext - //do - // let options = new CustomEditorOptions (editor.Options) - // editor.MimeType <- "text/x-fsharp" - // editor.ContextMenuPath <- "/MonoDevelop/SourceEditor2/ContextMenu/Fsi" - // options.ShowLineNumberMargin <- false - // options.TabsToSpaces <- true - // options.ShowWhitespaces <- ShowWhitespaces.Never - // ctx.CompletionWidget <- editor.GetContent() - // ctx.Editor <- editor - // editor.Options <- options let mutable killIntent = NoIntent - let mutable promptReceived = false let mutable activeDoc : IDisposable option = None let mutable lastLineOutput = None @@ -490,32 +330,6 @@ type FSharpInteractivePad() as this = let nonBreakingSpace = "\u00A0" // used to disable editor syntax highlighting for output - //let addMarker image = - // let data = editor.GetContent().GetTextEditorData() - // let textDocument = data.Document - - // let line = data.GetLineByOffset editor.Length - // let prompt = FsiPrompt image - - // textDocument.AddMarker(line, prompt) - - // textDocument.CommitUpdateAll() - - let setPrompt() = - () - //editor.InsertText(editor.Length, "\n") - //editor.ScrollTo editor.Length - //addMarker promptIcon - - //let renderImage image = - // let data = editor.GetContent().GetTextEditorData() - // let textDocument = data.Document - // let line = editor.GetLine editor.CaretLine - // let imageMarker = ImageRendererMarker(line, image) - // textDocument.AddMarker(editor.CaretLine, imageMarker) - // textDocument.CommitUpdateAll() - // editor.InsertAtCaret "\n" - let input = new ResizeArray<_>() let setupSession() = @@ -530,15 +344,12 @@ type FSharpInteractivePad() as this = this.Host.ShowAll() input.Clear() - promptReceived <- false - let textReceived = ses.TextReceived.Subscribe(fun t -> Runtime.RunInMainThread(fun () -> controller.FsiOutput t) |> ignore) + let textReceived = ses.TextReceived.Subscribe(fun t -> + Runtime.RunInMainThread(fun () -> controller.FsiOutput t) |> ignore) //let imageReceived = ses.ImageReceived.Subscribe(fun image -> Runtime.RunInMainThread(fun () -> renderImage image) |> Async.AwaitTask |> Async.RunSynchronously) - let promptReady = ses.PromptReady.Subscribe(fun () -> Runtime.RunInMainThread(fun () -> promptReceived <- true; controller.SetPrompt() ) |> ignore) + let promptReady = ses.PromptReady.Subscribe(fun () -> Runtime.RunInMainThread(fun () -> controller.SetPrompt() ) |> ignore) ses.Exited.Add(fun _ -> - textReceived.Dispose() - promptReady.Dispose() - //imageReceived.Dispose() if killIntent = NoIntent then Runtime.RunInMainThread(fun () -> LoggingService.LogDebug ("Interactive: process stopped") @@ -547,53 +358,18 @@ type FSharpInteractivePad() as this = Runtime.RunInMainThread (fun () -> controller.Clear()) |> ignore killIntent <- NoIntent) - ses.StartReceiving() - //editor.GrabFocus() Some(ses) with - | :? Exception as e -> + | e -> None let mutable session = None - let setCaretLine (s: string) = () - //let line = editor.GetLineByOffset editor.CaretOffset - //editor.ReplaceText(line.Offset, line.EndOffset - line.Offset, s) - let resetFsi intent = - if promptReceived then - killIntent <- intent - session |> Option.iter (fun (ses: InteractiveSession) -> ses.Kill()) - if intent = Restart then session <- setupSession() - - let history = ShellHistory() - //new() = - // let ctx = FsiDocumentContext() - // let doc = TextEditorFactory.CreateNewDocument() - // do - // doc.FileName <- FilePath ctx.Name - - // let editor = TextEditorFactory.CreateNewEditor(ctx, doc, TextEditorType.Default) - // new FSharpInteractivePad(editor) - - //member x.FsiOutput t : unit = - // if editor.CaretColumn <> 1 then - // editor.InsertAtCaret ("\n") - // editor.InsertAtCaret (nonBreakingSpace + t) - // editor.CaretOffset <- editor.Text.Length - // editor.ScrollTo editor.CaretLocation - // lastLineOutput <- Some editor.CaretLine - - //member x.Text = - // editor.Text - - //member x.SetPrompt() = - // editor.InsertText(editor.Length, "\n") - // editor.ScrollTo editor.Length - // addMarker promptIcon - - //member x.AddMorePrompt() = - // addMarker newLineIcon + input.Clear() + killIntent <- intent + this.Controller |> Option.iter (fun controller -> controller.Clear()) + session |> Option.iter (fun (ses:InteractiveSession) -> ses.Restart()) member x.Session = session @@ -601,14 +377,6 @@ type FSharpInteractivePad() as this = do LoggingService.LogDebug ("Interactive: Shutdown()!") resetFsi Kill - //member x.SendCommandAndStore command = - // let fileName = getActiveDocumentFileName() - // input.Add command - // session - // |> Option.iter(fun ses -> - // history.Push command - // ses.SendInput (command + "\n") fileName) - member x.SendCommand command = let fileName = getActiveDocumentFileName() @@ -617,33 +385,10 @@ type FSharpInteractivePad() as this = |> Option.iter(fun ses -> ses.SendInput (command + ";;") fileName) - //member x.RequestCompletions lineStr column = - // session - // |> Option.iter(fun ses -> - // ses.SendCompletionRequest lineStr (column + 1)) - - //member x.RequestTooltip symbol = - // session - // |> Option.iter(fun ses -> ses.SendTooltipRequest symbol) - - //member x.RequestParameterHint lineStr column = - // session - // |> Option.iter(fun ses -> - // ses.SendParameterHintRequest lineStr (column + 1)) - - member x.ProcessCommandHistoryUp () = - history.Up() - |> Option.iter setCaretLine - - member x.ProcessCommandHistoryDown () = - history.Down() - |> function Some c -> setCaretLine c | None -> setCaretLine "" - override x.Dispose() = LoggingService.LogDebug ("Interactive: disposing pad...") activeDoc |> Option.iter (fun ad -> ad.Dispose()) x.Shutdown() - //editor.Dispose() override x.Control = Control.op_Implicit x.Host @@ -711,14 +456,7 @@ type FSharpInteractivePad() as this = member val Controller:InteractivePadController option = None with get, set override x.Initialize(container:MonoDevelop.Ide.Gui.IPadWindow) = - //this.Controller <- Some controller - //controller.ConsoleInput += OnViewConsoleInput; - //controller.Editable <- true; - LoggingService.LogDebug ("InteractivePad: created!") - //editor.MimeType <- "text/x-fsharp" - //ctx.CompletionWidget <- editor.GetContent() - //ctx.Editor <- editor let toolbar = container.GetToolbar(DockPositionType.Right) let addButton(icon, action, tooltip) = @@ -733,7 +471,6 @@ type FSharpInteractivePad() as this = addButton ("gtk-refresh", (fun _ -> x.RestartFsi()), GettextCatalog.GetString ("Reset")) toolbar.ShowAll() session <- setupSession() - //editor.RunWhenRealized(fun () -> session <- setupSession()) member x.RestartFsi() = resetFsi Restart @@ -750,7 +487,7 @@ type FSharpInteractivePad() as this = else dlg.SelectedFile.ChangeExtension(".fsx") - let lines = []// input |> Seq.map (fun line -> line.TrimEnd(';')) + let lines = input |> Seq.map (fun line -> line.TrimEnd(';')) let fileContent = String.concat "\n" lines File.WriteAllText(file.FullPath.ToString(), fileContent) @@ -882,110 +619,6 @@ type InteractivePadCompletionDownHandler let (controller: InteractivePadController) = downcast textView.Properties.[typeof] controller.HistoryDown() true -/// handles keypresses for F# Interactive -//type FSharpFsiEditorCompletion() = -// inherit TextEditorExtension() -// override x.IsValidInContext(context) = -// context :? FsiDocumentContext - -// override x.KeyPress (descriptor:KeyDescriptor) = -// match FSharpInteractivePad.Fsi with -// | Some fsi -> -// let getLineText (editor:TextEditor) (line:IDocumentLine) = -// if line.Length > 0 then -// editor.GetLineText line -// else -// "" - -// let getInputLines (editor:TextEditor) = -// let lineNumbers = -// match fsi.LastOutputLine with -// | Some lineNumber -> -// [ lineNumber+1 .. editor.CaretLine ] -// | None -> [ editor.CaretLine ] -// lineNumbers -// |> List.map editor.GetLine -// |> List.map (getLineText editor) - -// let result = -// match descriptor.SpecialKey with -// | SpecialKey.Return -> -// if x.Editor.CaretLine = x.Editor.LineCount then -// let lines = getInputLines x.Editor -// lines -// |> List.iter(fun (lineStr) -> -// fsi.SendCommandAndStore lineStr) - -// let line = x.Editor.GetLine x.Editor.CaretLine -// let lineStr = getLineText x.Editor line -// x.Editor.CaretOffset <- line.EndOffset -// x.Editor.InsertAtCaret "\n" - -// if not (lineStr.TrimEnd().EndsWith(";;")) then -// fsi.AddMorePrompt() -// fsi.LastOutputLine <- Some line.LineNumber -// false -// | SpecialKey.Up -> -// if x.Editor.CaretLine = x.Editor.LineCount then -// fsi.ProcessCommandHistoryUp() -// false -// else -// base.KeyPress (descriptor) -// | SpecialKey.Down -> -// if x.Editor.CaretLine = x.Editor.LineCount then -// fsi.ProcessCommandHistoryDown() -// false -// else -// base.KeyPress (descriptor) -// | SpecialKey.Left -> -// if (x.Editor.CaretLine <> x.Editor.LineCount) || x.Editor.CaretColumn > 1 then -// base.KeyPress (descriptor) -// else -// false -// | SpecialKey.BackSpace -> -// if x.Editor.CaretLine = x.Editor.LineCount && x.Editor.CaretColumn > 1 then -// base.KeyPress (descriptor) -// else -// false -// | _ -> -// if x.Editor.CaretLine <> x.Editor.LineCount then -// x.Editor.CaretOffset <- x.Editor.Length -// base.KeyPress (descriptor) - -// result -// | _ -> base.KeyPress (descriptor) - -// member x.clipboardHandler = x.Editor.GetContent() - -// [] -// member x.Cut() = x.clipboardHandler.Cut() - -// [] -// member x.CanCut(ci:CommandInfo) = -// ci.Enabled <- x.clipboardHandler.EnableCut - -// [] -// member x.Copy() = x.clipboardHandler.Copy() - -// [] -// member x.CanCopy(ci:CommandInfo) = -// ci.Enabled <- x.clipboardHandler.EnableCopy - -// [] -// member x.Paste() = x.clipboardHandler.Paste() - -// [] -// member x.CanPaste(ci:CommandInfo) = -// ci.Enabled <- x.clipboardHandler.EnablePaste - -// [] -// member x.ZoomIn() = x.Editor.GetContent().ZoomIn() - -// [] -// member x.ZoomOut() = x.Editor.GetContent().ZoomOut() - -// [] -// member x.ZoomReset() = x.Editor.GetContent().ZoomReset() type InteractiveCommand(command) = inherit CommandHandler() @@ -1032,25 +665,3 @@ type RestartFsi() = type ClearFsi() = inherit InteractiveCommand(fun fsi -> fsi.ClearFsi()) - -//open System.ComponentModel.Composition -//open Microsoft.VisualStudio.Text.Editor -//open MonoDevelop.TextEditor -////open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor -////open Microsoft.VisualStudio.FSharp.Editor -//open Microsoft.VisualStudio.Threading - -//[)>] -//[] -//[] -//[] -//type internal FSharpPathedDocumentExtensionProvider -// [] -// ( -// //fsharpCheckerProvider: FSharpCheckerProvider, -// //optionsManager: FSharpProjectOptionsManagerk, -// joinableTaskContext: JoinableTaskContext -// ) as x = -// inherit EditorContentInstanceProvider() - -// override x.CreateInstance(view) = new FSharpPathedDocumentExtension(optionsManager, fsharpCheckerProvider.Checker, view, joinableTaskContext) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs index d3ee4dea6e3..6cccc8bda7d 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs @@ -33,8 +33,6 @@ module binaryDeserializer = Some o type InteractiveSession(pathToExe) = - let jsonSettings = JsonSerializerSettings(ReferenceLoopHandling = ReferenceLoopHandling.Ignore, TypeNameHandling = TypeNameHandling.Auto) - let (|Completion|_|) (command: string) = if command.StartsWith("completion ") then let payload = command.[11..] @@ -73,7 +71,15 @@ type InteractiveSession(pathToExe) = let mutable waitingForResponse = false - let fsiProcess = + let textReceived = Event<_>() + let promptReady = Event<_>() + + let completionsReceivedEvent = new Event() + let imageReceivedEvent = new Event() + let tooltipReceivedEvent = new Event() + let parameterHintReceivedEvent = new Event<(FSharpNoteworthyParamInfoLocations * FSharpMethodGroup) option>() + + let startProcess() = let processPid = sprintf " %d" (Process.GetCurrentProcess().Id) let processName = @@ -89,57 +95,60 @@ type InteractiveSession(pathToExe) = RedirectStandardInput = true, StandardErrorEncoding = Text.Encoding.UTF8, StandardOutputEncoding = Text.Encoding.UTF8) try - Process.Start(startInfo) + let proc = Process.Start(startInfo) + LoggingService.logDebug "Process started %d" proc.Id + proc.BeginOutputReadLine() + proc.BeginErrorReadLine() + + proc.OutputDataReceived + |> Event.filter (fun de -> de.Data <> null) + |> Event.add (fun de -> + LoggingService.logDebug "Interactive: received %s" de.Data + match de.Data with + | Image image -> imageReceivedEvent.Trigger image + | ServerPrompt -> promptReady.Trigger() + | data -> + if data.Trim() <> "" then + if waitingForResponse then waitingForResponse <- false + textReceived.Trigger(data + "\n")) + + proc.ErrorDataReceived.Subscribe(fun de -> + if not (String.IsNullOrEmpty de.Data) then + try + match de.Data with + | Completion completions -> + completionsReceivedEvent.Trigger completions + | Tooltip tooltip -> + tooltipReceivedEvent.Trigger tooltip + | ParameterHints hints -> + parameterHintReceivedEvent.Trigger hints + | _ -> LoggingService.logDebug "[fsharpi] don't know how to process command %s" de.Data + + with + | :? JsonException as e -> + LoggingService.logError "[fsharpi] - error deserializing error stream - %s\\n %s" e.Message de.Data + ) |> ignore + + proc.EnableRaisingEvents <- true + proc with e -> - LoggingService.LogDebug (sprintf "Interactive: Error %s" (e.ToString())) + LoggingService.logDebug "Interactive: Error %s" (e.ToString()) reraise() - let textReceived = Event<_>() - let promptReady = Event<_>() + let mutable fsiProcess = startProcess() let sendCommand(str:string) = waitingForResponse <- true - LoggingService.LogDebug (sprintf "Interactive: sending %s" str) - let stream = fsiProcess.StandardInput.BaseStream - let bytes = Text.Encoding.UTF8.GetBytes(str + "\n") - stream.Write(bytes,0,bytes.Length) - stream.Flush() + LoggingService.logDebug "Interactive: sending %s" str + LoggingService.logDebug "send command %d" fsiProcess.Id + + async { + let stream = fsiProcess.StandardInput.BaseStream + let bytes = Text.Encoding.UTF8.GetBytes(str + "\n") + do! stream.WriteAsync(bytes,0,bytes.Length) |> Async.AwaitTask + stream.Flush() + } |> Async.Start - let completionsReceivedEvent = new Event() - let imageReceivedEvent = new Event() - let tooltipReceivedEvent = new Event() - let parameterHintReceivedEvent = new Event<(FSharpNoteworthyParamInfoLocations * FSharpMethodGroup) option>() - do - fsiProcess.OutputDataReceived - |> Event.filter (fun de -> de.Data <> null) - |> Event.add (fun de -> - LoggingService.logDebug "Interactive: received %s" de.Data - match de.Data with - | Image image -> imageReceivedEvent.Trigger image - | ServerPrompt -> promptReady.Trigger() - | data -> - if data.Trim() <> "" then - if waitingForResponse then waitingForResponse <- false - textReceived.Trigger(data + "\n")) - - fsiProcess.ErrorDataReceived.Subscribe(fun de -> - if not (String.IsNullOrEmpty de.Data) then - try - match de.Data with - | Completion completions -> - completionsReceivedEvent.Trigger completions - | Tooltip tooltip -> - tooltipReceivedEvent.Trigger tooltip - | ParameterHints hints -> - parameterHintReceivedEvent.Trigger hints - | _ -> LoggingService.logDebug "[fsharpi] don't know how to process command %s" de.Data - - with - | :? JsonException as e -> - LoggingService.logError "[fsharpi] - error deserializing error stream - %s\\n %s" e.Message de.Data - ) |> ignore - - fsiProcess.EnableRaisingEvents <- true member x.Interrupt() = LoggingService.logDebug "Interactive: Break!" @@ -148,22 +157,28 @@ type InteractiveSession(pathToExe) = member x.TooltipReceived = tooltipReceivedEvent.Publish member x.ParameterHintReceived = parameterHintReceivedEvent.Publish member x.ImageReceived = imageReceivedEvent.Publish - member x.StartReceiving() = - fsiProcess.BeginOutputReadLine() - fsiProcess.BeginErrorReadLine() + //member x.StartReceiving() = + // fsiProcess.BeginOutputReadLine() + // fsiProcess.BeginErrorReadLine() member x.TextReceived = textReceived.Publish member x.PromptReady = promptReady.Publish member x.HasExited() = fsiProcess.HasExited + + + member x.Restart() = + fsiProcess.Kill() + fsiProcess <- startProcess() + member x.Kill() = - if not fsiProcess.HasExited then - x.SendInput "#q;;" None - for i in 0 .. 10 do - if not fsiProcess.HasExited then - LoggingService.logDebug "Interactive: waiting for process exit after #q... %d" (i*200) - fsiProcess.WaitForExit(200) |> ignore + //if not fsiProcess.HasExited then + // x.SendInput "#q;;" None + // for i in 0 .. 10 do + // if not fsiProcess.HasExited then + // LoggingService.logDebug "Interactive: waiting for process exit after #q... %d" (i*200) + // fsiProcess.WaitForExit(200) |> ignore if not fsiProcess.HasExited then fsiProcess.Kill() diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveWorkspace.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveWorkspace.fs index 9d7fa1457c5..0c4e7ec01b8 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveWorkspace.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveWorkspace.fs @@ -26,27 +26,10 @@ namespace FSharp.Editor open Microsoft.CodeAnalysis -open MonoDevelop.Ide.Composition -open System - -open System -open System.Collections.Concurrent -open System.Collections.Immutable -open System.ComponentModel.Composition -open System.IO -open System.Linq -open System.Threading -open System.Threading.Tasks -open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.CSharp -open Microsoft.CodeAnalysis.Host -open Microsoft.CodeAnalysis.Scripting open Microsoft.CodeAnalysis.Text -open Microsoft.VisualStudio.Composition open Microsoft.VisualStudio.Text -open Mono.Addins -open MonoDevelop.Core open MonoDevelop.Ide.Composition + type InteractiveWorkspace() = inherit Workspace(CompositionManager.Instance.HostServices, WorkspaceKind.MiscellaneousFiles) with member x.CreateDocument(buffer: ITextBuffer) = From 8383b0fce41bec98fcf4797b510f1f69e0b4a401 Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 27 Apr 2020 12:12:08 +0100 Subject: [PATCH 083/101] Clean up --- .../FSharp.Editor/Common/LanguageService.fs | 5 -- .../VSMac/InteractiveClassificationService.fs | 45 +++++++----------- .../src/FSharp.Editor/VSMac/SignatureHelp.fs | 46 +------------------ 3 files changed, 17 insertions(+), 79 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Common/LanguageService.fs b/vsintegration/src/FSharp.Editor/Common/LanguageService.fs index 52ab586420e..f370517a8ab 100644 --- a/vsintegration/src/FSharp.Editor/Common/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/Common/LanguageService.fs @@ -2,16 +2,12 @@ open System open System.Collections.Generic open System.IO -open System.Diagnostics open FSharp.Compiler open FSharp.Compiler.SourceCodeServices -open FSharp.Compiler.Text open MonoDevelop.FSharp open MonoDevelop.Core open MonoDevelop.Ide -open MonoDevelop.Ide.TypeSystem open MonoDevelop.Projects -//type LoggingService = MonoDevelop.FSharp.LoggingService open Microsoft.VisualStudio.FSharp.Editor.Extensions module Symbol = @@ -28,7 +24,6 @@ module Symbol = else (beginLine, beginCol) Range.mkPos beginLine beginCol, Range.mkPos endLine endCol - //(beginLine, beginCol), (endLine, endCol) /// Contains settings of the F# language service module ServiceSettings = diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs index 0e34f46e839..06214b0a640 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs @@ -25,25 +25,15 @@ // THE SOFTWARE. namespace Microsoft.VisualStudio.FSharp.Editor -open System open System.Composition open System.Collections.Generic -open System.Diagnostics open System.Threading open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Classification -open Microsoft.CodeAnalysis.Editor -open Microsoft.CodeAnalysis.Host.Mef open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Classification -open Microsoft.VisualStudio.Text.Classification -open System.Windows.Media -open MonoDevelop.Core -open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor -//[, FSharpContentTypeNames.FSharpInteractiveContentType)>] -//[] [)>] type internal FSharpInteractiveClassificationService [] @@ -53,28 +43,25 @@ type internal FSharpInteractiveClassificationService interface IFSharpInteractiveClassificationService with member __.AddLexicalClassifications(sourceText: SourceText, textSpan: TextSpan, result: List, cancellationToken: CancellationToken) = - //let line = sourceText.Lines.GetLineFromPosition(textSpan.Start).LineNumber - - //if FSharpInteractivePad.Fsi.Value.Controller.Value.IsInputLine(line) then - //service.AddLexicalClassifications(sourceText, textSpan, result, cancellationToken) () member __.AddSyntacticClassificationsAsync(document: Document, textSpan: TextSpan, result: List, cancellationToken: CancellationToken) = - //Tasks.Task.CompletedTask - match document.TryGetText() with - | true, sourceText -> - let line = sourceText.Lines.GetLineFromPosition(textSpan.Start).LineNumber - - if FSharpInteractivePad.Fsi.Value.Controller.Value.IsInputLine(line) then - //let service = document.Project.LanguageServices.GetService(); - - service.AddSyntacticClassificationsAsync(document, textSpan, result, cancellationToken) - else - Tasks.Task.CompletedTask - | false, _ -> Tasks.Task.CompletedTask - - //member __.AddSemanticClassificationsAsync(document: Document, textSpan: TextSpan, result: List, cancellationToken: CancellationToken) = - // System.Threading.Tasks.Task.CompletedTask + let classificationTask = + maybe { + match document.TryGetText() with + | true, sourceText -> + let line = sourceText.Lines.GetLineFromPosition(textSpan.Start).LineNumber + let! fsi = FSharpInteractivePad.Fsi + let! controller = fsi.Controller + if controller.IsInputLine(line) then + return! service.AddSyntacticClassificationsAsync(document, textSpan, result, cancellationToken) |> Some + else + return! None + | false, _ -> return! None + } + match classificationTask with + | Some classifications -> classifications + | None -> Tasks.Task.CompletedTask // Do not perform classification if we don't have project options (#defines matter) member __.AdjustStaleClassification(_: SourceText, classifiedSpan: ClassifiedSpan) : ClassifiedSpan = classifiedSpan diff --git a/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs index 479ef9dc4f6..27988b6f58d 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs @@ -2,18 +2,14 @@ namespace Microsoft.VisualStudio.FSharp.Editor -open System open System.Composition open System.Collections.Generic open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.SignatureHelp open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.ExternalAccess.FSharp.SignatureHelp open Microsoft.VisualStudio.Text -////open Microsoft.VisualStudio.Shell -//open Microsoft.VisualStudio.Shell.Interop open FSharp.Compiler.Layout open FSharp.Compiler.Range @@ -25,41 +21,21 @@ open MonoDevelop.FSharp type internal FSharpInteractiveSignatureHelpProvider [] ( - //serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager ) = static let userOpName = "SignatureHelpProvider" - let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder((*serviceProvider.XMLMemberIndexService*)) + let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder() static let oneColAfter (lp: LinePosition) = LinePosition(lp.Line,lp.Character+1) static let oneColBefore (lp: LinePosition) = LinePosition(lp.Line,max 0 (lp.Character-1)) // Unit-testable core routine static member internal ProvideMethodsAsyncAux(nwpl:FSharpNoteworthyParamInfoLocations, methodGroup:FSharpMethodGroup, documentationBuilder: IDocumentationBuilder, sourceText: SourceText, caretPosition: int, triggerIsTypedChar: char option) = async { - ////let (interactiveSession: InteractiveSession) = downcast textView.Properties.[typeof] - - //let! parseResults, checkFileAnswer = checker.ParseAndCheckFileInProject(filePath, textVersionHash, sourceText.ToFSharpSourceText(), options, userOpName = userOpName) - //match checkFileAnswer with - //| FSharpCheckFileAnswer.Aborted -> return None - //| FSharpCheckFileAnswer.Succeeded(checkFileResults) -> let textLines = sourceText.Lines let caretLinePos = textLines.GetLinePosition(caretPosition) - let caretLineColumn = caretLinePos.Character - - //// Get the parameter locations - //let paramLocations = parseResults.FindNoteworthyParamInfoLocations(Pos.fromZ 0 caretLineColumn) - - //match paramLocations with - //| None -> return None // no locations = no help - //| Some nwpl -> - //let names = nwpl.LongId - //let lidEnd = nwpl.LongIdEndLocation - - // Get the methods - //let! methodGroup = checkFileResults.GetMethods(lidEnd.Line, lidEnd.Column, "", Some names) let methods = methodGroup.Methods @@ -182,9 +158,6 @@ type internal FSharpInteractiveSignatureHelpProvider let suffixParts = [| TaggedText(TextTags.Punctuation, (if isStaticArgTip then ">" else ")")) |] let completionItem = (method.HasParamArrayArg, documentation, prefixParts, separatorParts, suffixParts, parameters, mainDescription) - // FSROSLYNTODO: Do we need a cache like for completion? - //declarationItemsCache.Remove(completionItem.DisplayText) |> ignore // clear out stale entries if they exist - //declarationItemsCache.Add(completionItem.DisplayText, declarationItem) results.Add(completionItem) @@ -193,37 +166,20 @@ type internal FSharpInteractiveSignatureHelpProvider } interface IFSharpInteractiveSignatureHelpProvider with - //member this.IsTriggerCharacter(c) = c ='(' || c = '<' || c = ',' - //member this.IsRetriggerCharacter(c) = c = ')' || c = '>' || c = '=' - member this.GetItemsAsync(document, position, triggerInfo, cancellationToken) = asyncMaybe { try let! fsi = FSharpInteractivePad.Fsi let! controller = fsi.Controller - //let (interactiveSession: InteractiveSession) = downcast controller.View.Properties.[typeof] - - //if FSharpInteractivePad.Fsi.Value.Controller.Value.IsInputLine(line) then - - //let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) - let! sourceText = document.GetTextAsync(cancellationToken) let line = sourceText.Lines.GetLineFromPosition(position) let column = position - line.Start let snapshot = sourceText.FindCorrespondingEditorTextSnapshot() let lineText = snapshot.GetText(Span(line.Start, line.End - line.Start)) - //let fssourceText = SourceText.From(lineText).ToFSharpSourceText() MonoDevelop.Core.LoggingService.LogDebug("parameter-hints " + column.ToString() + " " + lineText) controller.Session.SendParameterHintRequest lineText column let! paramInfo, methodGroups = controller.Session.ParameterHintReceived |> Async.AwaitEvent - //let! textVersion = document.GetTextVersionAsync(cancellationToken) - ////let! parseResult, parsedInput, checkResults = checkerProvider.Checker.ParseAndCheckDocument(document, projectOptions, lineText) - //let! projectOptions, errors = checkerProvider.Checker.GetProjectOptionsFromScript(document.FilePath, fssourceText) |> liftAsync - //let parsingOptions, errors = checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions) - //let! parseResult = checkerProvider.Checker.ParseFileNoCache(document.FilePath, fssourceText, parsingOptions) |> liftAsync - //let ino = parseResult.FindNoteworthyParamInfoLocations(Pos.fromZ 0 column) - //printfn "%A" ino let triggerTypedChar = if triggerInfo.TriggerCharacter.HasValue && triggerInfo.TriggerReason = FSharpSignatureHelpTriggerReason.TypeCharCommand then Some triggerInfo.TriggerCharacter.Value From 7a593f2c1e8be235f8bf70e69fb84c349623351e Mon Sep 17 00:00:00 2001 From: nosami Date: Tue, 28 Apr 2020 14:24:47 +0100 Subject: [PATCH 084/101] Fix key handling and refactor --- .../Completion/CompletionService.fs | 2 - .../src/FSharp.Editor/FSharp.Editor.fsproj | 1 + .../src/FSharp.Editor/FSharp.addin.xml | 3 +- .../Navigation/GoToDefinitionService.fs | 1 - .../FSharp.Editor/VSMac/CompletionService.fs | 6 +- .../VSMac/InteractiveClassificationService.fs | 2 +- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 164 +++--------------- .../VSMac/InteractivePadKeyHandlers.fs | 155 +++++++++++++++++ .../FSharp.Editor/VSMac/InteractiveSession.fs | 49 +++--- .../src/FSharp.Editor/VSMac/SignatureHelp.fs | 10 +- 10 files changed, 209 insertions(+), 184 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/VSMac/InteractivePadKeyHandlers.fs diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index ed19e75eff6..d09ea4d7bff 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -57,8 +57,6 @@ type internal FSharpCompletionService .WithDismissIfLastCharacterDeleted(true) .WithDefaultEnterKeyRule(enterKeyRule) -[] -[, FSharpConstants.FSharpContentTypeName)>] type internal FSharpCompletionSource (textView: ITextView, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider) = diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 9b165720c7b..48116b502bb 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -264,6 +264,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index 69ae8a2a1e5..0f5abd45d06 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -61,13 +61,13 @@ + \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs index 41f7df14823..7f2f9ba0ad8 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs @@ -2,7 +2,6 @@ namespace Microsoft.VisualStudio.FSharp.Editor -open System.Composition open System.Threading open System.Threading.Tasks diff --git a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs index 2526a680707..ab017591823 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs @@ -2,7 +2,8 @@ namespace Microsoft.VisualStudio.FSharp.Editor -open System.Composition +open System +open System.ComponentModel.Composition open System.Collections.Immutable open Microsoft.CodeAnalysis @@ -11,7 +12,6 @@ open Microsoft.CodeAnalysis.Host.Mef open Microsoft.CodeAnalysis.ExternalAccess.FSharp open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion -open System.ComponentModel.Composition open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion open Microsoft.VisualStudio.Text.Editor open System.Threading.Tasks @@ -61,8 +61,6 @@ type internal FSharpInteractiveCompletionService .WithDismissIfLastCharacterDeleted(true) .WithDefaultEnterKeyRule(enterKeyRule) -[] -[, FSharpContentTypeNames.FSharpInteractiveContentType)>] type internal FSharpInteractiveCompletionSource (textView: ITextView, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider) = diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs index 06214b0a640..9970397a32d 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveClassificationService.fs @@ -25,7 +25,7 @@ // THE SOFTWARE. namespace Microsoft.VisualStudio.FSharp.Editor -open System.Composition +open System.ComponentModel.Composition open System.Collections.Generic open System.Threading diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index 0902e8eae81..a9cabcd4747 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -136,7 +136,6 @@ type InteractiveGlyphFactoryProvider() as this = let imageId = ImageId(Guid("{3404e281-57a6-4f3a-972b-185a683e0753}"), 1) upcast InteractiveGlyphFactory(imageId, x.ImageService) - type InteractivePromptGlyphTagger(textView: ITextView) as this = let tagsChanged = Event<_,_>() @@ -178,6 +177,7 @@ type InteractivePadController(session: InteractiveSession) as this = let textBuffer = textBufferFactory.CreateTextBuffer("", contentType) let textView = factory.CreateTextView(textBuffer, roles) + let workspace = new InteractiveWorkspace() let history = ShellHistory() do @@ -284,9 +284,9 @@ type InteractivePadController(session: InteractiveSession) as this = let glyphManager = InteractiveGlyphManagerService.getGlyphManager(textView) inputLines.Add(snapshot.LineCount - 1) |> ignore + glyphManager.AddPrompt lastLine.Start.Position scrollToLastLine() updateReadOnlyRegion() - glyphManager.AddPrompt lastLine.Start.Position member this.HistoryUp() = history.Up() |> Option.iter setCaretLine @@ -328,12 +328,10 @@ type FSharpInteractivePad() as this = else None else None - let nonBreakingSpace = "\u00A0" // used to disable editor syntax highlighting for output - let input = new ResizeArray<_>() let setupSession() = - try + //try let pathToExe = Path.Combine(Reflection.Assembly.GetExecutingAssembly().Location |> Path.GetDirectoryName, "MonoDevelop.FSharpInteractive.Service.exe") |> ProcessArgumentBuilder.Quote @@ -342,26 +340,26 @@ type FSharpInteractivePad() as this = this.Controller <- Some controller this.Host <- new GtkNSViewHost(controller.View) this.Host.ShowAll() - input.Clear() let textReceived = ses.TextReceived.Subscribe(fun t -> Runtime.RunInMainThread(fun () -> controller.FsiOutput t) |> ignore) //let imageReceived = ses.ImageReceived.Subscribe(fun image -> Runtime.RunInMainThread(fun () -> renderImage image) |> Async.AwaitTask |> Async.RunSynchronously) let promptReady = ses.PromptReady.Subscribe(fun () -> Runtime.RunInMainThread(fun () -> controller.SetPrompt() ) |> ignore) - ses.Exited.Add(fun _ -> - if killIntent = NoIntent then - Runtime.RunInMainThread(fun () -> - LoggingService.LogDebug ("Interactive: process stopped") - (*this.FsiOutput "\nSession termination detected. Press Enter to restart." *))|> ignore - elif killIntent = Restart then - Runtime.RunInMainThread (fun () -> controller.Clear()) |> ignore - killIntent <- NoIntent) - - Some(ses) - with - | e -> - None + //ses.Exited.Add(fun _ -> + // if killIntent = NoIntent then + // Runtime.RunInMainThread(fun () -> + // LoggingService.LogDebug ("Interactive: process stopped") + // (*this.FsiOutput "\nSession termination detected. Press Enter to restart." *))|> ignore + // elif killIntent = Restart then + // Runtime.RunInMainThread (fun () -> controller.Clear()) |> ignore + // killIntent <- NoIntent) + + //Some(ses) + ses + //with + //| e -> + // None let mutable session = None @@ -470,7 +468,11 @@ type FSharpInteractivePad() as this = addButton ("gtk-clear", (fun _ -> x.ClearFsi()), GettextCatalog.GetString ("Clear")) addButton ("gtk-refresh", (fun _ -> x.RestartFsi()), GettextCatalog.GetString ("Reset")) toolbar.ShowAll() - session <- setupSession() + let ses = setupSession() + session <- ses |> Some + + //container.PadShown.Add(fun _args -> session <- setupSession()) + container.PadContentShown.Add(fun _args -> if not ses.HasStarted then ses.StartReceiving() |> ignore) member x.RestartFsi() = resetFsi Restart @@ -498,128 +500,6 @@ type FSharpInteractivePad() as this = let file = dlg.SelectedFile x.SendCommand ("#load @\"" + file.FullPath.ToString() + "\"") -[] -[] -[)>] -type InteractivePadCompletionTypeCharHandler - [] - ( completionBroker:ICompletionBroker, - signatureHelpBroker:ISignatureHelpBroker ) = - interface ICommandHandler with - member x.DisplayName = "InteractivePadTypeCharHandler" - member x.GetCommandState _args = CommandState.Available - - member x.ExecuteCommand(args, _context) = - if args.TypedChar <> '(' && args.TypedChar <> ',' && args.TypedChar <> ' ' then - signatureHelpBroker.DismissAllSessions(args.TextView) - let textView = args.TextView - let (controller: InteractivePadController) = downcast textView.Properties.[typeof] - controller.EnsureLastLine() - false - -[] -[] -[)>] -type InteractivePadCompletionBackspaceHandler - [] - ( completionBroker:ICompletionBroker ) = - - interface ICommandHandler with - member x.DisplayName = "InteractivePadKeyBackspaceHandler" - member x.GetCommandState _args = CommandState.Available - - member x.ExecuteCommand(args, _context) = - let textView = args.TextView - let snapshot = textView.TextBuffer.CurrentSnapshot - let lineCount = snapshot.LineCount - - if lineCount > 0 then - let line = snapshot.GetLineFromLineNumber(lineCount - 1) - if textView.Caret.Position.BufferPosition.Position > line.Start.Position then - false - else - true - else - true - -[] -[] -[)>] -type InteractivePadCompletionReturnHandler - [] - ( completionBroker:ICompletionBroker, - signatureHelpBroker:ISignatureHelpBroker ) = - interface ICommandHandler with - member x.DisplayName = "InteractivePadKeyReturnHandler" - member x.GetCommandState _args = CommandState.Available - - member x.ExecuteCommand(args, context) = - let textView = args.TextView - signatureHelpBroker.DismissAllSessions(textView) - if completionBroker.IsCompletionActive(textView) then - false - else - let (controller: InteractivePadController) = downcast textView.Properties.[typeof] - - let textBuffer = textView.TextBuffer - let snapshot = textBuffer.CurrentSnapshot - let position = textView.Caret.Position.BufferPosition.Position - let line = snapshot.GetLineFromPosition(position) - - if line.Length > 0 then - let start = line.Start.Position - let finish = line.End.Position - let start = Math.Min(start, finish); - let span = new Span(start, finish - start) - let text = snapshot.GetText(span) - controller.FsiOutput "\n" - controller.FsiInput text - true - -[] -[] -[)>] -type InteractivePadCompletionUpHandler - [] - ( completionBroker:ICompletionBroker, - signatureHelpBroker:ISignatureHelpBroker ) = - interface ICommandHandler with - member x.DisplayName = "InteractivePadKeyUpHandler" - member x.GetCommandState _args = CommandState.Available - - member x.ExecuteCommand(args, context) = - if signatureHelpBroker.IsSignatureHelpActive(args.TextView) then - false - else if completionBroker.IsCompletionActive(args.TextView) then - false - else - let textView = args.TextView - let (controller: InteractivePadController) = downcast textView.Properties.[typeof] - controller.HistoryUp() - true - -[] -[] -[)>] -type InteractivePadCompletionDownHandler - [] - ( completionBroker:ICompletionBroker, - signatureHelpBroker:ISignatureHelpBroker ) = - interface ICommandHandler with - member x.DisplayName = "InteractivePadKeyDownHandler" - member x.GetCommandState _args = CommandState.Available - - member x.ExecuteCommand(args, context) = - if signatureHelpBroker.IsSignatureHelpActive(args.TextView) then - false - else if completionBroker.IsCompletionActive(args.TextView) then - false - else - let textView = args.TextView - let (controller: InteractivePadController) = downcast textView.Properties.[typeof] - controller.HistoryDown() - true - type InteractiveCommand(command) = inherit CommandHandler() diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePadKeyHandlers.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePadKeyHandlers.fs new file mode 100644 index 00000000000..c704445d11f --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePadKeyHandlers.fs @@ -0,0 +1,155 @@ +// +// InteractivePadKeyHandlers.fs +// +// Author: +// jasonimison +// +// Copyright (c) 2020 Microsoft +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +namespace Microsoft.VisualStudio.FSharp.Editor + +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +open System.ComponentModel.Composition +open Microsoft.VisualStudio.Language.Intellisense +open Microsoft.VisualStudio.Text.Editor.Commanding.Commands +open Microsoft.VisualStudio.Commanding +open Microsoft.VisualStudio.Text + +[] +[] +[)>] +type InteractivePadCompletionReturnHandler + [] + ( completionBroker:ICompletionBroker, + signatureHelpBroker:ISignatureHelpBroker ) = + interface ICommandHandler with + member x.DisplayName = "InteractivePadKeyReturnHandler" + member x.GetCommandState _args = CommandState.Available + + member x.ExecuteCommand(args, context) = + let textView = args.TextView + signatureHelpBroker.DismissAllSessions(textView) + if completionBroker.IsCompletionActive(textView) then + false + else + let (controller: InteractivePadController) = downcast textView.Properties.[typeof] + + let textBuffer = textView.TextBuffer + let snapshot = textBuffer.CurrentSnapshot + let position = textView.Caret.Position.BufferPosition.Position + let line = snapshot.GetLineFromPosition(position) + + if line.Length > 0 then + let start = line.Start.Position + let finish = line.End.Position + let start = min start finish + let span = Span(start, finish - start) + let text = snapshot.GetText(span) + controller.FsiOutput "\n" + controller.FsiInput text + true + +[] +[] +[)>] +type InteractivePadCompletionTypeCharHandler + [] + ( completionBroker:ICompletionBroker, + signatureHelpBroker:ISignatureHelpBroker ) = + interface ICommandHandler with + member x.DisplayName = "InteractivePadTypeCharHandler" + member x.GetCommandState _args = CommandState.Available + + member x.ExecuteCommand(args, _context) = + if args.TypedChar <> '(' && args.TypedChar <> ',' && args.TypedChar <> ' ' then + signatureHelpBroker.DismissAllSessions(args.TextView) + let textView = args.TextView + let (controller: InteractivePadController) = downcast textView.Properties.[typeof] + controller.EnsureLastLine() + false + +[] +[] +[)>] +type InteractivePadCompletionBackspaceHandler + [] + ( completionBroker:ICompletionBroker ) = + + interface ICommandHandler with + member x.DisplayName = "InteractivePadKeyBackspaceHandler" + member x.GetCommandState _args = CommandState.Available + + member x.ExecuteCommand(args, _context) = + let textView = args.TextView + let snapshot = textView.TextBuffer.CurrentSnapshot + let lineCount = snapshot.LineCount + + if lineCount > 0 then + let line = snapshot.GetLineFromLineNumber(lineCount - 1) + if textView.Caret.Position.BufferPosition.Position > line.Start.Position then + false + else + true + else + true + +[] +[] +[)>] +type InteractivePadCompletionUpHandler + [] + ( completionBroker:ICompletionBroker, + signatureHelpBroker:ISignatureHelpBroker ) = + interface ICommandHandler with + member x.DisplayName = "InteractivePadKeyUpHandler" + member x.GetCommandState _args = CommandState.Available + + member x.ExecuteCommand(args, context) = + if signatureHelpBroker.IsSignatureHelpActive(args.TextView) then + false + else if completionBroker.IsCompletionActive(args.TextView) then + false + else + let textView = args.TextView + let (controller: InteractivePadController) = downcast textView.Properties.[typeof] + controller.HistoryUp() + true + +[] +[] +[)>] +type InteractivePadCompletionDownHandler + [] + ( completionBroker:ICompletionBroker, + signatureHelpBroker:ISignatureHelpBroker ) = + interface ICommandHandler with + member x.DisplayName = "InteractivePadKeyDownHandler" + member x.GetCommandState _args = CommandState.Available + + member x.ExecuteCommand(args, context) = + if signatureHelpBroker.IsSignatureHelpActive(args.TextView) then + false + else if completionBroker.IsCompletionActive(args.TextView) then + false + else + let textView = args.TextView + let (controller: InteractivePadController) = downcast textView.Properties.[typeof] + controller.HistoryDown() + true diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs index 6cccc8bda7d..137341ae62b 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs @@ -69,8 +69,6 @@ type InteractiveSession(pathToExe) = else None - let mutable waitingForResponse = false - let textReceived = Event<_>() let promptReady = Event<_>() @@ -79,6 +77,7 @@ type InteractiveSession(pathToExe) = let tooltipReceivedEvent = new Event() let parameterHintReceivedEvent = new Event<(FSharpNoteworthyParamInfoLocations * FSharpMethodGroup) option>() + let mutable hasStarted = false let startProcess() = let processPid = sprintf " %d" (Process.GetCurrentProcess().Id) @@ -109,7 +108,6 @@ type InteractiveSession(pathToExe) = | ServerPrompt -> promptReady.Trigger() | data -> if data.Trim() <> "" then - if waitingForResponse then waitingForResponse <- false textReceived.Trigger(data + "\n")) proc.ErrorDataReceived.Subscribe(fun de -> @@ -130,15 +128,15 @@ type InteractiveSession(pathToExe) = ) |> ignore proc.EnableRaisingEvents <- true + hasStarted <- true proc with e -> LoggingService.logDebug "Interactive: Error %s" (e.ToString()) reraise() - let mutable fsiProcess = startProcess() + let mutable fsiProcess = Unchecked.defaultof let sendCommand(str:string) = - waitingForResponse <- true LoggingService.logDebug "Interactive: sending %s" str LoggingService.logDebug "send command %d" fsiProcess.Id @@ -149,7 +147,6 @@ type InteractiveSession(pathToExe) = stream.Flush() } |> Async.Start - member x.Interrupt() = LoggingService.logDebug "Interactive: Break!" @@ -157,37 +154,33 @@ type InteractiveSession(pathToExe) = member x.TooltipReceived = tooltipReceivedEvent.Publish member x.ParameterHintReceived = parameterHintReceivedEvent.Publish member x.ImageReceived = imageReceivedEvent.Publish - //member x.StartReceiving() = - // fsiProcess.BeginOutputReadLine() - // fsiProcess.BeginErrorReadLine() - member x.TextReceived = textReceived.Publish member x.PromptReady = promptReady.Publish + member x.StartReceiving() = fsiProcess <- startProcess() + member x.HasStarted = hasStarted member x.HasExited() = fsiProcess.HasExited - - member x.Restart() = fsiProcess.Kill() fsiProcess <- startProcess() - member x.Kill() = - //if not fsiProcess.HasExited then - // x.SendInput "#q;;" None - // for i in 0 .. 10 do - // if not fsiProcess.HasExited then - // LoggingService.logDebug "Interactive: waiting for process exit after #q... %d" (i*200) - // fsiProcess.WaitForExit(200) |> ignore - - if not fsiProcess.HasExited then - fsiProcess.Kill() - for i in 0 .. 10 do - if not fsiProcess.HasExited then - LoggingService.logDebug "Interactive: waiting for process exit after kill... %d" (i*200) - fsiProcess.WaitForExit(200) |> ignore - - member x.KillNow() = fsiProcess.Kill() + //member x.Kill() = + // //if not fsiProcess.HasExited then + // // x.SendInput "#q;;" None + // // for i in 0 .. 10 do + // // if not fsiProcess.HasExited then + // // LoggingService.logDebug "Interactive: waiting for process exit after #q... %d" (i*200) + // // fsiProcess.WaitForExit(200) |> ignore + + // if not fsiProcess.HasExited then + // fsiProcess.Kill() + // for i in 0 .. 10 do + // if not fsiProcess.HasExited then + // LoggingService.logDebug "Interactive: waiting for process exit after kill... %d" (i*200) + // fsiProcess.WaitForExit(200) |> ignore + + //member x.KillNow() = fsiProcess.Kill() member x.SendInput input documentName = documentName diff --git a/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs index 27988b6f58d..c1459db5875 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. namespace Microsoft.VisualStudio.FSharp.Editor - -open System.Composition +open System +open System.ComponentModel.Composition open System.Collections.Generic open Microsoft.CodeAnalysis @@ -16,13 +16,13 @@ open FSharp.Compiler.Range open FSharp.Compiler.SourceCodeServices open MonoDevelop.FSharp -[] +[] [)>] type internal FSharpInteractiveSignatureHelpProvider [] ( - checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + //checkerProvider: FSharpCheckerProvider, + //projectInfoManager: FSharpProjectOptionsManager ) = static let userOpName = "SignatureHelpProvider" From 9feb3aeb6c91b5e88eab2e2d59cb9e04d3ad209b Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 29 Apr 2020 11:55:53 +0100 Subject: [PATCH 085/101] extract glyph code to separate file --- .../src/FSharp.Editor/FSharp.Editor.fsproj | 1 + .../FSharp.Editor/VSMac/InteractiveGlyph.fs | 92 +++++++++++++++++++ .../src/FSharp.Editor/VSMac/InteractivePad.fs | 73 --------------- 3 files changed, 93 insertions(+), 73 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/VSMac/InteractiveGlyph.fs diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 48116b502bb..1b76077b7f1 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -256,6 +256,7 @@ + {AF5FEAD5-B50E-4F07-A274-32F23D5C504D} diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveGlyph.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveGlyph.fs new file mode 100644 index 00000000000..4c1b260ad5e --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveGlyph.fs @@ -0,0 +1,92 @@ +// +// InteractiveGlyph.fs +// +// Author: +// jasonimison +// +// Copyright (c) 2020 Microsoft +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +namespace Microsoft.VisualStudio.FSharp.Editor + +open Microsoft.VisualStudio.Text.Editor +open Microsoft.VisualStudio.Core.Imaging +open System.ComponentModel.Composition +open Microsoft.VisualStudio.Text.Tagging +open System +open System.Collections.Generic +open Microsoft.VisualStudio.Text +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor + +type InteractivePromptGlyphTag() = interface IGlyphTag + +type InteractiveGlyphFactory(imageId:ImageId, imageService:IImageService) = + let mutable imageCache: AppKit.NSImage option = None + + interface IGlyphFactory with + member x.GenerateGlyph(line, tag) = + match tag with + | :? InteractivePromptGlyphTag -> + if imageCache.IsNone then + imageCache <- Some(imageService.GetImage (imageId) :?> AppKit.NSImage) + let imageView = AppKit.NSImageView.FromImage imageCache.Value + imageView.SetFrameSize (imageView.FittingSize) + Some (box imageView) + | _ -> None + |> Option.toObj + +[)>] +[] +[] +[)>] +type InteractiveGlyphFactoryProvider() as this = + [] + member val ImageService:IImageService = null with get, set + + interface IGlyphFactoryProvider with + member x.GetGlyphFactory(view, margin) = + let imageId = ImageId(Guid("{3404e281-57a6-4f3a-972b-185a683e0753}"), 1) + upcast InteractiveGlyphFactory(imageId, x.ImageService) + +type InteractivePromptGlyphTagger(textView: ITextView) as this = + let tagsChanged = Event<_,_>() + + let promptSpans = HashSet<_>() + + do + textView.Properties.[typeof] <- this + + member x.AddPrompt(pos:int) = + if promptSpans.Add(pos) then + tagsChanged.Trigger(this, SnapshotSpanEventArgs(SnapshotSpan(textView.TextSnapshot, pos, 1))) + + interface ITagger with + [] + member this.TagsChanged = tagsChanged.Publish + + member x.GetTags(spans) = + seq { + for span in spans do + if promptSpans.Contains(span.Start.Position) then + yield TagSpan(span, InteractivePromptGlyphTag()) + } + +module InteractiveGlyphManagerService = + let getGlyphManager(textView: ITextView) = + textView.Properties.GetOrCreateSingletonProperty(typeof, fun () -> InteractivePromptGlyphTagger textView) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index a9cabcd4747..b706dee98ae 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -29,20 +29,15 @@ open System open System.Collections.Generic open System.ComponentModel.Composition open System.IO - open FSharp.Editor -open Gdk open Gtk open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor -open Microsoft.VisualStudio.Commanding open Microsoft.VisualStudio.Core.Imaging open Microsoft.VisualStudio.FSharp.Editor -open Microsoft.VisualStudio.Language.Intellisense open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor -open Microsoft.VisualStudio.Text.Editor.Commanding.Commands open Microsoft.VisualStudio.Text.Tagging open MonoDevelop.Components open MonoDevelop.Components.Commands @@ -52,18 +47,6 @@ open MonoDevelop.Core.Execution open MonoDevelop.FSharp open MonoDevelop.Ide open MonoDevelop.Ide.Composition -[] -module ColorHelpers = - let strToColor s = - let c = ref (Color()) - match Color.Parse (s, c) with - | true -> !c - | false -> Color() // black is as good a guess as any here - - let colorToStr (c:Color) = - sprintf "#%04X%04X%04X" c.Red c.Green c.Blue - - let cairoToGdk (c:Cairo.Color) = GtkUtil.ToGdkColor(c) type FSharpCommands = | ShowFSharpInteractive = 0 @@ -106,62 +89,6 @@ type ShellHistory() = else Some history.[nextDown] -type InteractivePromptGlyphTag() = interface IGlyphTag - -type InteractiveGlyphFactory(imageId:ImageId, imageService:IImageService) = - let mutable imageCache: AppKit.NSImage option = None - - interface IGlyphFactory with - member x.GenerateGlyph(line, tag) = - match tag with - | :? InteractivePromptGlyphTag -> - if imageCache.IsNone then - imageCache <- Some(imageService.GetImage (imageId) :?> AppKit.NSImage) - let imageView = AppKit.NSImageView.FromImage imageCache.Value - imageView.SetFrameSize (imageView.FittingSize) - Some (box imageView) - | _ -> None - |> Option.toObj - -[)>] -[] -[] -[)>] -type InteractiveGlyphFactoryProvider() as this = - [] - member val ImageService:IImageService = null with get, set - - interface IGlyphFactoryProvider with - member x.GetGlyphFactory(view, margin) = - let imageId = ImageId(Guid("{3404e281-57a6-4f3a-972b-185a683e0753}"), 1) - upcast InteractiveGlyphFactory(imageId, x.ImageService) - -type InteractivePromptGlyphTagger(textView: ITextView) as this = - let tagsChanged = Event<_,_>() - - let promptSpans = HashSet<_>() - - do - textView.Properties.[typeof] <- this - - member x.AddPrompt(pos:int) = - if promptSpans.Add(pos) then - tagsChanged.Trigger(this, SnapshotSpanEventArgs(SnapshotSpan(textView.TextSnapshot, pos, 1))) - - interface ITagger with - [] - member this.TagsChanged = tagsChanged.Publish - - member x.GetTags(spans) = - seq { - for span in spans do - if promptSpans.Contains(span.Start.Position) then - yield TagSpan(span, InteractivePromptGlyphTag()) - } - -module InteractiveGlyphManagerService = - let getGlyphManager(textView: ITextView) = - textView.Properties.GetOrCreateSingletonProperty(typeof, fun () -> InteractivePromptGlyphTagger textView) [] [] From b3af7a0ff84d26b3fd3b12d5d64e4330a982bcc7 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 29 Apr 2020 13:23:51 +0100 Subject: [PATCH 086/101] Fix off by one error --- vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index b706dee98ae..4beeb0d1874 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -224,7 +224,7 @@ type InteractivePadController(session: InteractiveSession) as this = member this.EnsureLastLine() = getLastLine() |> Option.iter(fun line -> - if textView.Caret.Position.BufferPosition.Position <= line.Start.Position then + if textView.Caret.Position.BufferPosition.Position < line.Start.Position then textView.Caret.MoveTo(line.End) |> ignore) [)>] From e53600889621e520495a0a88f85126672df25626 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 29 Apr 2020 14:50:20 +0100 Subject: [PATCH 087/101] Make interactive glyph prompt appear at the correct time --- .../FSharp.Editor/VSMac/InteractiveGlyph.fs | 18 ++++++++++++++++-- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveGlyph.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveGlyph.fs index 4c1b260ad5e..7a968f90e1a 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveGlyph.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveGlyph.fs @@ -69,6 +69,20 @@ type InteractivePromptGlyphTagger(textView: ITextView) as this = let promptSpans = HashSet<_>() + let getLastLine() = + let snapshot = textView.TextBuffer.CurrentSnapshot + let lineCount = snapshot.LineCount + + if lineCount > 0 then + Some (snapshot.GetLineFromLineNumber(lineCount - 1)) + else + None + + let isOnLastLine(pos:int) = + match getLastLine() with + | Some line -> line.Start.Position = pos + | None -> false + do textView.Properties.[typeof] <- this @@ -83,10 +97,10 @@ type InteractivePromptGlyphTagger(textView: ITextView) as this = member x.GetTags(spans) = seq { for span in spans do - if promptSpans.Contains(span.Start.Position) then + if promptSpans.Contains(span.Start.Position) || isOnLastLine(span.Start.Position) then yield TagSpan(span, InteractivePromptGlyphTag()) } module InteractiveGlyphManagerService = - let getGlyphManager(textView: ITextView) = + let interactiveGlyphTagger(textView: ITextView) = textView.Properties.GetOrCreateSingletonProperty(typeof, fun () -> InteractivePromptGlyphTagger textView) diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index 4beeb0d1874..b146c416a16 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -208,10 +208,10 @@ type InteractivePadController(session: InteractiveSession) as this = let buffer = textView.TextBuffer let snapshot = buffer.CurrentSnapshot let lastLine = snapshot.GetLineFromLineNumber(snapshot.LineCount - 1) - let glyphManager = InteractiveGlyphManagerService.getGlyphManager(textView) + let glyphTagger = InteractiveGlyphManagerService.interactiveGlyphTagger(textView) inputLines.Add(snapshot.LineCount - 1) |> ignore - glyphManager.AddPrompt lastLine.Start.Position + glyphTagger.AddPrompt lastLine.Start.Position scrollToLastLine() updateReadOnlyRegion() From 2582daca648281e4f573c55ef5d7f32dc8e29b46 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 29 Apr 2020 20:02:15 +0100 Subject: [PATCH 088/101] Don't block UI thread for go to definition --- .../Navigation/GoToDefinition.fs | 2 +- .../Navigation/GoToDefinitionService.fs | 58 +++++++++++-------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs index f8455527f54..0480df18dfc 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs @@ -219,7 +219,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP return implSymbol.RangeAlternate } - member private this.FindDefinitionAtPosition(originDocument: Document, position: int) = + member this.FindDefinitionAtPosition(originDocument: Document, position: int) = asyncMaybe { let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(originDocument, CancellationToken.None) let! sourceText = originDocument.GetTextAsync () |> liftTaskAsync diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs index 7f2f9ba0ad8..9be89261984 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs @@ -89,28 +89,36 @@ type internal FSharpGoToDefinitionService /// Invoked with Go to Definition. /// Try to navigate to the definiton of the symbol at the symbolRange in the originDocument member __.TryGoToDefinition(document: Document, position: int, cancellationToken: CancellationToken) = - statusBar.Message(SR.LocatingSymbol()) - use __ = statusBar.Animate() - - let gtdTask = gtd.FindDefinitionTask(document, position, cancellationToken) - - // Wrap this in a try/with as if the user clicks "Cancel" on the thread dialog, we'll be cancelled. - // Task.Wait throws an exception if the task is cancelled, so be sure to catch it. - try - // This call to Wait() is fine because we want to be able to provide the error message in the status bar. - gtdTask.Wait() - if gtdTask.Status = TaskStatus.RanToCompletion && gtdTask.Result.IsSome then - let item, _ = gtdTask.Result.Value - gtd.NavigateToItem(item, statusBar) - - // 'true' means do it, like Sheev Palpatine would want us to. - true - else - statusBar.TempMessage (SR.CannotDetermineSymbol()) - false - with exc -> - statusBar.TempMessage(String.Format(SR.NavigateToFailed(), Exception.flattenMessage exc)) - - // Don't show the dialog box as it's most likely that the user cancelled. - // Don't make them click twice. - true \ No newline at end of file + let computation = + async { + + statusBar.Message(SR.LocatingSymbol()) + use __ = statusBar.Animate() + + let! position = gtd.FindDefinitionAtPosition(document, position) + + match position with + | Some (item, _) -> + + // Wrap this in a try/with as if the user clicks "Cancel" on the thread dialog, we'll be cancelled. + // Task.Wait throws an exception if the task is cancelled, so be sure to catch it. + //try + // This call to Wait() is fine because we want to be able to provide the error message in the status bar. + //gtdTask.Wait() + //if gtdTask.Status = TaskStatus.RanToCompletion && gtdTask.Result.IsSome then + gtd.NavigateToItem(item, statusBar) + + // 'true' means do it, like Sheev Palpatine would want us to. + //true + | None -> + statusBar.TempMessage (SR.CannotDetermineSymbol()) + //false + //with exc -> + // statusBar.TempMessage(String.Format(SR.NavigateToFailed(), Exception.flattenMessage exc)) + + // // Don't show the dialog box as it's most likely that the user cancelled. + // // Don't make them click twice. + // true + } + Async.StartImmediate(computation, cancellationToken) + true \ No newline at end of file From 2ba31a2f77dfce634d364c883ba15316967af801 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 30 Apr 2020 11:21:50 +0100 Subject: [PATCH 089/101] Clean up --- .../ClassificationDefinitions.fs | 186 ------ .../FSharp.Editor/CodeFix/FixIndexerAccess.fs | 2 +- .../CodeFix/ProposeUppercaseLabel.fs | 3 +- .../CodeFix/RemoveUnusedOpens.fs | 1 - .../CodeLens/CodeLensProvider.fs | 106 ---- .../CodeLens/FSharpCodeLensService.fs | 4 +- .../Commands/FsiCommandService.fs | 91 --- .../Commands/XmlDocCommandService.fs | 2 +- .../src/FSharp.Editor/Common/AssemblyInfo.fs | 11 - .../src/FSharp.Editor/Common/FSharpProject.fs | 1 - .../src/FSharp.Editor/Common/FileService.fs | 52 -- .../FSharp.Editor/Common/LanguageService.fs | 544 ------------------ .../src/FSharp.Editor/Common/Logger.fs | 1 - .../FSharp.Editor/Common/MDLanguageService.fs | 173 ------ .../AsyncCompletionCommitManagerProvider.fs | 24 - .../Completion/CompletionProvider.fs | 64 +-- .../Completion/CompletionService.fs | 6 +- .../Completion/CompletionUtils.fs | 28 - .../FSharp.Editor/Completion/SignatureHelp.fs | 9 +- .../Diagnostics/DocumentDiagnosticAnalyzer.fs | 3 - .../UnusedOpensDiagnosticAnalyzer.fs | 13 - .../DocComments/XMLDocumentation.fs | 38 +- .../src/FSharp.Editor/FSharp.Editor.fsproj | 6 - .../src/FSharp.Editor/FSharp.addin.xml | 114 ++-- .../LanguageService/FSharpCheckerProvider.fs | 1 - .../LanguageService/FSharpContentType.fs | 3 +- .../FSharpProjectOptionsManager.fs | 126 +--- .../LanguageService/LanguageService.fs | 196 ------- 28 files changed, 78 insertions(+), 1730 deletions(-) delete mode 100644 vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs delete mode 100644 vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs delete mode 100644 vsintegration/src/FSharp.Editor/Commands/FsiCommandService.fs delete mode 100644 vsintegration/src/FSharp.Editor/Common/AssemblyInfo.fs delete mode 100644 vsintegration/src/FSharp.Editor/Common/MDLanguageService.fs delete mode 100644 vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManagerProvider.fs diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs deleted file mode 100644 index c65f0c70f0c..00000000000 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. - -namespace Microsoft.VisualStudio.FSharp.Editor - -open System -open System.ComponentModel.Composition -open System.Windows.Media - -open Microsoft.VisualStudio -open Microsoft.VisualStudio.Editor -//open Microsoft.VisualStudio.PlatformUI -//open Microsoft.VisualStudio.Shell -//open Microsoft.VisualStudio.Shell.Interop -//open Microsoft.Internal.VisualStudio.Shell.Interop -open Microsoft.VisualStudio.Language.StandardClassification -open Microsoft.VisualStudio.Text.Classification -//open Microsoft.VisualStudio.Utilities -open Microsoft.CodeAnalysis.Classification - -open FSharp.Compiler.SourceCodeServices - -[] -module internal FSharpClassificationTypes = - let [] Function = "FSharp.Function" - let [] MutableVar = "FSharp.MutableVar" - let [] Printf = "FSharp.Printf" - let [] ReferenceType = ClassificationTypeNames.ClassName - let [] Module = ClassificationTypeNames.ModuleName - let [] ValueType = ClassificationTypeNames.StructName - let [] Keyword = ClassificationTypeNames.Keyword - let [] Enum = ClassificationTypeNames.EnumName - let [] Property = "FSharp.Property" - let [] Interface = ClassificationTypeNames.InterfaceName - let [] TypeArgument = ClassificationTypeNames.TypeParameterName - let [] Operator = ClassificationTypeNames.Operator - let [] Disposable = "FSharp.Disposable" - - let getClassificationTypeName = function - | SemanticClassificationType.ReferenceType -> ReferenceType - | SemanticClassificationType.Module -> Module - | SemanticClassificationType.ValueType -> ValueType - | SemanticClassificationType.Function -> Function - | SemanticClassificationType.MutableVar -> MutableVar - | SemanticClassificationType.Printf -> Printf - | SemanticClassificationType.ComputationExpression - | SemanticClassificationType.IntrinsicFunction -> Keyword - | SemanticClassificationType.UnionCase - | SemanticClassificationType.Enumeration -> Enum - | SemanticClassificationType.Property -> Property - | SemanticClassificationType.Interface -> Interface - | SemanticClassificationType.TypeArgument -> TypeArgument - | SemanticClassificationType.Operator -> Operator - | SemanticClassificationType.Disposable -> Disposable - -module internal ClassificationDefinitions = - - [] - [)>] - type internal ThemeColors - [] - ( - //classificationformatMapService: IClassificationFormatMapService, - //classificationTypeRegistry: IClassificationTypeRegistryService, - [)>] serviceProvider: IServiceProvider - ) = - - let (| LightTheme | DarkTheme | UnknownTheme |) id = - if id = KnownColorThemes.Light || id = KnownColorThemes.Blue || id = Guids.blueHighContrastThemeId then LightTheme - elif id = KnownColorThemes.Dark then DarkTheme - else UnknownTheme - - let getCurrentThemeId() = - let themeService = serviceProvider.GetService(typeof) :?> IVsColorThemeService - themeService.CurrentTheme.ThemeId - - //let colorData = // name, (light, dark) - //[ FSharpClassificationTypes.Function, (Colors.Black, Color.FromRgb(220uy, 220uy, 220uy)) - //FSharpClassificationTypes.MutableVar, (Color.FromRgb(160uy, 128uy, 0uy), Color.FromRgb(255uy, 210uy, 28uy)) - //FSharpClassificationTypes.Printf, (Color.FromRgb(43uy, 145uy, 175uy), Color.FromRgb(78uy, 220uy, 176uy)) - //FSharpClassificationTypes.Property, (Colors.Black, Color.FromRgb(220uy, 220uy, 220uy)) - //FSharpClassificationTypes.Disposable, (Color.FromRgb(43uy, 145uy, 175uy), Color.FromRgb(78uy, 220uy, 176uy)) ] - - - let setColors _ = - let fontAndColorStorage = serviceProvider.GetService(typeof) :?> IVsFontAndColorStorage - let fontAndColorCacheManager = serviceProvider.GetService(typeof) :?> IVsFontAndColorCacheManager - fontAndColorCacheManager.CheckCache( ref DefGuidList.guidTextEditorFontCategory) |> ignore - fontAndColorStorage.OpenCategory(ref DefGuidList.guidTextEditorFontCategory, uint32 __FCSTORAGEFLAGS.FCSF_READONLY) |> ignore - - // let formatMap = classificationformatMapService.GetClassificationFormatMap(category = "text") - // try - // formatMap.BeginBatchUpdate() - // //for ctype, (light, dark) in colorData do - // //// we don't touch the changes made by the user - // //if fontAndColorStorage.GetItem(ctype, Array.zeroCreate 1) <> VSConstants.S_OK then - // //let ict = classificationTypeRegistry.GetClassificationType(ctype) - // //let oldProps = formatMap.GetTextProperties(ict) - // //let newProps = oldProps //match getCurrentThemeId() with - // // //| LightTheme -> oldProps.SetForeground light - // // //| DarkTheme -> oldProps.SetForeground dark - // // //| UnknownTheme -> oldProps - // //formatMap.SetTextProperties(ict, newProps) - // fontAndColorStorage.CloseCategory() |> ignore - // finally formatMap.EndBatchUpdate() - - //let handler = ThemeChangedEventHandler setColors - //do VSColorTheme.add_ThemeChanged handler - interface IDisposable with member __.Dispose() = ()// VSColorTheme.remove_ThemeChanged handler - - member __.GetColor(_ctype) = - //let light, dark = colorData |> Map.ofList |> Map.find ctype - match getCurrentThemeId() with - | LightTheme -> Nullable() - | DarkTheme -> Nullable() - | UnknownTheme -> Nullable() - - interface ISetThemeColors with member this.SetColors() = setColors() - - - //[] - //let FSharpFunctionClassificationType : ClassificationTypeDefinition = null - - //[] - //let FSharpMutableVarClassificationType : ClassificationTypeDefinition = null - - //[] - //let FSharpPrintfClassificationType : ClassificationTypeDefinition = null - - //[] - //let FSharpPropertyClassificationType : ClassificationTypeDefinition = null - - //[] - //let FSharpDisposableClassificationType : ClassificationTypeDefinition = null - - //[)>] - //[] - //[] - //[] - //[] - //type internal FSharpFunctionTypeFormat() as self = - // inherit ClassificationFormatDefinition() - - // do self.DisplayName <- SR.FSharpFunctionsOrMethodsClassificationType() - - //[)>] - //[] - //[] - //[] - //[] - //type internal FSharpMutableVarTypeFormat [](theme: ThemeColors) as self = - // inherit ClassificationFormatDefinition() - - // do self.DisplayName <- SR.FSharpMutableVarsClassificationType() - // self.ForegroundColor <- theme.GetColor FSharpClassificationTypes.MutableVar - - //[)>] - //[] - //[] - //[] - //[] - //type internal FSharpPrintfTypeFormat [](theme: ThemeColors) as self = - // inherit ClassificationFormatDefinition() - - // do self.DisplayName <- SR.FSharpPrintfFormatClassificationType() - // self.ForegroundColor <- theme.GetColor FSharpClassificationTypes.Printf - - //[)>] - //[] - //[] - //[] - //[] - //type internal FSharpPropertyFormat() as self = - // inherit ClassificationFormatDefinition() - - // do self.DisplayName <- SR.FSharpPropertiesClassificationType() - - //[)>] - //[] - //[] - //[] - //[] - //type internal FSharpDisposableFormat [](theme: ThemeColors) as self = - //inherit ClassificationFormatDefinition() - - //do self.DisplayName <- SR.FSharpDisposablesClassificationType() - //self.ForegroundColor <- theme.GetColor FSharpClassificationTypes.Disposable \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/CodeFix/FixIndexerAccess.fs b/vsintegration/src/FSharp.Editor/CodeFix/FixIndexerAccess.fs index 71660a0ffc2..bc53e35fbd7 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/FixIndexerAccess.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/FixIndexerAccess.fs @@ -48,7 +48,7 @@ type internal FSharpFixIndexerAccessCodeFixProvider() = let codefix = CodeFixHelpers.createTextChangeCodeFix( - "Add Indexer Dot", + Microsoft.VisualStudio.UI.GettextCatalog.GetString "Add Indexer Dot", //CompilerDiagnostics.getErrorMessage AddIndexerDot, context, (fun () -> asyncMaybe.Return [| TextChange(span, replacement.TrimEnd() + ".") |])) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs b/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs index 2198d45c494..06ac261d7f2 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs @@ -6,7 +6,6 @@ open System.Composition open System.Threading.Tasks open Microsoft.CodeAnalysis.CodeFixes open Microsoft.CodeAnalysis.CodeActions -open FSharp.Compiler.SourceCodeServices [] type internal FSharpProposeUpperCaseLabelCodeFixProvider @@ -25,7 +24,7 @@ type internal FSharpProposeUpperCaseLabelCodeFixProvider asyncMaybe { let textChanger (originalText: string) = originalText.[0].ToString().ToUpper() + originalText.Substring(1) let! solutionChanger, originalText = SymbolHelpers.changeAllSymbolReferences(context.Document, context.Span, textChanger, projectInfoManager, checkerProvider.Checker, userOpName) - let title = originalText// CompilerDiagnostics.getErrorMessage (ReplaceWithSuggestion <| textChanger originalText) + let title = textChanger originalText context.RegisterCodeFix( CodeAction.Create(title, solutionChanger, title), context.Diagnostics |> Seq.filter (fun x -> fixableDiagnosticIds |> List.contains x.Id) |> Seq.toImmutableArray) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs index c89282eea3a..8b659aafb32 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs @@ -5,7 +5,6 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System.Composition open System.Threading open System.Threading.Tasks -open System.Threading.Tasks open Microsoft.CodeAnalysis.Diagnostics open Microsoft.CodeAnalysis.Text diff --git a/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs b/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs deleted file mode 100644 index e44fb978c05..00000000000 --- a/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. - -namespace rec Microsoft.VisualStudio.FSharp.Editor - -open System -open Microsoft.VisualStudio.Text -open Microsoft.VisualStudio.Text.Editor -open System.ComponentModel.Composition -open Microsoft.VisualStudio.Utilities -//open Microsoft.VisualStudio.Shell -open Microsoft.VisualStudio -open Microsoft.VisualStudio.LanguageServices -open Microsoft.VisualStudio.Text.Tagging -open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.Shared.Utilities -open MonoDevelop.Ide -open MonoDevelop.Ide.TypeSystem - -[)>] -[)>] -[)>] -[] -[] -type internal CodeLensProvider - [] - ( - //[)>] serviceProvider: IServiceProvider, - textDocumentFactory: ITextDocumentFactoryService, - checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager, - typeMap : FSharpClassificationTypeMap Lazy, - settings: EditorOptions - ) = - - let lineLensProvider = ResizeArray() - let taggers = ResizeArray() - //let componentModel = Package.GetGlobalService(typeof) :?> ComponentModelHost.IComponentModel - //let workspace = componentModel.GetService() - let workspace = IdeApp.TypeSystemService.Workspace :?> MonoDevelopWorkspace - - /// Returns an provider for the textView if already one has been created. Else create one. - let addCodeLensProviderOnce wpfView buffer = - let res = taggers |> Seq.tryFind(fun (view, _) -> view = wpfView) - match res with - | Some (_, (tagger, _)) -> tagger - | None -> - let documentId = - lazy ( - match textDocumentFactory.TryGetTextDocument(buffer) with - | true, textDocument -> - Seq.tryHead (workspace.CurrentSolution.GetDocumentIdsWithFilePath(textDocument.FilePath)) - | _ -> None - |> Option.get - ) - - let tagger = CodeLensGeneralTagger(wpfView, buffer) - let service = FSharpCodeLensService(serviceProvider, workspace, documentId, buffer, checkerProvider.Checker, projectInfoManager, componentModel.GetService(), typeMap, tagger, settings) - let provider = (wpfView, (tagger, service)) - wpfView.Closed.Add (fun _ -> taggers.Remove provider |> ignore) - taggers.Add((wpfView, (tagger, service))) - tagger - - /// Returns an provider for the textView if already one has been created. Else create one. - let addLineLensProviderOnce wpfView buffer = - let res = lineLensProvider |> Seq.tryFind(fun (view, _) -> view = wpfView) - match res with - | None -> - let documentId = - lazy ( - match textDocumentFactory.TryGetTextDocument(buffer) with - | true, textDocument -> - Seq.tryHead (workspace.CurrentSolution.GetDocumentIdsWithFilePath(textDocument.FilePath)) - | _ -> None - |> Option.get - ) - let service = FSharpCodeLensService(serviceProvider, workspace, documentId, buffer, checkerProvider.Checker, projectInfoManager, componentModel.GetService(), typeMap, LineLensDisplayService(wpfView, buffer), settings) - let provider = (wpfView, service) - wpfView.Closed.Add (fun _ -> lineLensProvider.Remove provider |> ignore) - lineLensProvider.Add(provider) - | _ -> () - - [); Name("CodeLens"); - Order(Before = PredefinedAdornmentLayers.Text); - TextViewRole(PredefinedTextViewRoles.Document)>] - member val CodeLensAdornmentLayerDefinition : AdornmentLayerDefinition = null with get, set - - [); Name("LineLens"); - Order(Before = PredefinedAdornmentLayers.Text); - TextViewRole(PredefinedTextViewRoles.Document)>] - member val LineLensAdornmentLayerDefinition : AdornmentLayerDefinition = null with get, set - - interface IViewTaggerProvider with - override __.CreateTagger(view, buffer) = - if settings.CodeLens.Enabled && not settings.CodeLens.ReplaceWithLineLens then - let wpfView = - match view with - | :? ICocoaTextView as view -> view - | _ -> failwith "error" - - box(addCodeLensProviderOnce wpfView buffer) :?> _ - else - null - - interface ICocoaTextViewCreationListener with - override __.TextViewCreated view = - if settings.CodeLens.Enabled && settings.CodeLens.ReplaceWithLineLens then - addLineLensProviderOnce view (view.TextBuffer) |> ignore \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs b/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs index 308a1f467c2..21a70f89e2e 100644 --- a/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs +++ b/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs @@ -7,9 +7,9 @@ open System open System.Collections.Generic open System.Threading open System.Windows -//open System.Windows.Controls +open System.Windows.Controls open System.Windows.Media -//open System.Windows.Media.Animation +open System.Windows.Media.Animation open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Editor.Shared.Extensions diff --git a/vsintegration/src/FSharp.Editor/Commands/FsiCommandService.fs b/vsintegration/src/FSharp.Editor/Commands/FsiCommandService.fs deleted file mode 100644 index 54d0ec50ce0..00000000000 --- a/vsintegration/src/FSharp.Editor/Commands/FsiCommandService.fs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. - -namespace Microsoft.VisualStudio.FSharp.Editor - -open System -open System.ComponentModel.Composition - -open Microsoft.VisualStudio -open Microsoft.VisualStudio.Editor -open Microsoft.VisualStudio.OLE.Interop -open Microsoft.VisualStudio.Text.Editor -open Microsoft.VisualStudio.TextManager.Interop -//open Microsoft.VisualStudio.Utilities -open Microsoft.VisualStudio.Shell -open Microsoft.VisualStudio.Shell.Interop -//open Microsoft.VisualStudio.FSharp.Interactive - -type internal FsiCommandFilter(serviceProvider: System.IServiceProvider) = - - let loadPackage (guidString: string) = - lazy( - let shell = serviceProvider.GetService(typeof) :?> IVsShell - let packageToBeLoadedGuid = ref (Guid(guidString)) - match shell.LoadPackage packageToBeLoadedGuid with - | VSConstants.S_OK, pkg -> - pkg :?> Package - | _ -> null) - - let fsiPackage = loadPackage FSharpConstants.fsiPackageGuidString - - let mutable nextTarget = null - - member x.AttachToViewAdapter (viewAdapter: IVsTextView) = - match viewAdapter.AddCommandFilter x with - | VSConstants.S_OK, next -> - nextTarget <- next - | errorCode, _ -> - ErrorHandler.ThrowOnFailure errorCode |> ignore - - interface IOleCommandTarget with - member x.Exec (pguidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut) = - if pguidCmdGroup = VSConstants.VsStd11 && nCmdId = uint32 VSConstants.VSStd11CmdID.ExecuteSelectionInInteractive then - Hooks.OnMLSend fsiPackage.Value FsiEditorSendAction.ExecuteSelection null null - VSConstants.S_OK - elif pguidCmdGroup = VSConstants.VsStd11 && nCmdId = uint32 VSConstants.VSStd11CmdID.ExecuteLineInInteractive then - Hooks.OnMLSend fsiPackage.Value FsiEditorSendAction.ExecuteLine null null - VSConstants.S_OK - elif pguidCmdGroup = Guids.guidInteractive && nCmdId = uint32 Guids.cmdIDDebugSelection then - Hooks.OnMLSend fsiPackage.Value FsiEditorSendAction.DebugSelection null null - VSConstants.S_OK - elif not (isNull nextTarget) then - nextTarget.Exec(&pguidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut) - else - VSConstants.E_FAIL - - member x.QueryStatus (pguidCmdGroup, cCmds, prgCmds, pCmdText) = - if pguidCmdGroup = VSConstants.VsStd11 then - for i = 0 to int cCmds-1 do - if prgCmds.[i].cmdID = uint32 VSConstants.VSStd11CmdID.ExecuteSelectionInInteractive then - prgCmds.[i].cmdf <- uint32 (OLECMDF.OLECMDF_SUPPORTED ||| OLECMDF.OLECMDF_ENABLED) - elif prgCmds.[i].cmdID = uint32 VSConstants.VSStd11CmdID.ExecuteLineInInteractive then - prgCmds.[i].cmdf <- uint32 (OLECMDF.OLECMDF_SUPPORTED ||| OLECMDF.OLECMDF_ENABLED ||| OLECMDF.OLECMDF_DEFHIDEONCTXTMENU) - VSConstants.S_OK - elif pguidCmdGroup = Guids.guidInteractive then - for i = 0 to int cCmds-1 do - if prgCmds.[i].cmdID = uint32 Guids.cmdIDDebugSelection then - let dbgState = Hooks.GetDebuggerState fsiPackage.Value - if dbgState = FsiDebuggerState.AttachedNotToFSI then - prgCmds.[i].cmdf <- uint32 OLECMDF.OLECMDF_INVISIBLE - else - prgCmds.[i].cmdf <- uint32 (OLECMDF.OLECMDF_SUPPORTED ||| OLECMDF.OLECMDF_ENABLED) - VSConstants.S_OK - elif not (isNull nextTarget) then - nextTarget.QueryStatus(&pguidCmdGroup, cCmds, prgCmds, pCmdText) - else - VSConstants.E_FAIL - -[)>] -[] -[] -type internal FsiCommandFilterProvider [] - ([)>] serviceProvider: System.IServiceProvider, - editorFactory: IVsEditorAdaptersFactoryService) = - interface IWpfTextViewCreationListener with - member __.TextViewCreated(textView) = - match editorFactory.GetViewAdapter(textView) with - | null -> () - | textViewAdapter -> - let commandFilter = FsiCommandFilter serviceProvider - commandFilter.AttachToViewAdapter textViewAdapter - \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs index 962354227af..8e22a3fb99a 100644 --- a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs +++ b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs @@ -13,7 +13,7 @@ open Microsoft.VisualStudio.OLE.Interop open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor open Microsoft.VisualStudio.TextManager.Interop -//open Microsoft.VisualStudio.Utilities +open Microsoft.VisualStudio.Utilities open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem open FSharp.Compiler.SourceCodeServices diff --git a/vsintegration/src/FSharp.Editor/Common/AssemblyInfo.fs b/vsintegration/src/FSharp.Editor/Common/AssemblyInfo.fs deleted file mode 100644 index e1a222bc412..00000000000 --- a/vsintegration/src/FSharp.Editor/Common/AssemblyInfo.fs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. - -namespace Microsoft.VisualStudio.FSharp.Editor - -//open Microsoft.VisualStudio.Shell - -// This is needed to load XAML resource dictionaries from FSharp.UIResources assembly because ProvideCodeBase attribute does not work for that purpose. -// This adds $PackageFolder$ to the directories probed for assemblies to load. -// The attribute is inexplicably class-targeted, hence the dummy class. -//[] -//type private BindingPathForUIResources = class end diff --git a/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs b/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs index 7085af97970..7c4d4ffcc76 100644 --- a/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs +++ b/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs @@ -9,7 +9,6 @@ open MonoDevelop.Projects open MonoDevelop.Projects.MSBuild open MonoDevelop.Core.Assemblies -//open ExtCore.Control open Microsoft.VisualStudio.FSharp.Editor.Pervasive module Project = let FSharp3Import = "$(MSBuildExtensionsPath32)\\..\\Microsoft SDKs\\F#\\3.0\\Framework\\v4.0\\Microsoft.FSharp.Targets" diff --git a/vsintegration/src/FSharp.Editor/Common/FileService.fs b/vsintegration/src/FSharp.Editor/Common/FileService.fs index b526aac027f..db80e1af359 100644 --- a/vsintegration/src/FSharp.Editor/Common/FileService.fs +++ b/vsintegration/src/FSharp.Editor/Common/FileService.fs @@ -4,65 +4,13 @@ open System.IO open MonoDevelop.Ide open MonoDevelop.Ide.Gui open MonoDevelop.Core -//open ExtCore.Control type Version = int type FileSystem (defaultFileSystem : IFileSystem, openDocuments: unit -> Document seq) = - let timestamps = new System.Collections.Generic.Dictionary() - let getOpenDoc filename = - let docs = openDocuments() - docs |> Seq.tryFind(fun d -> d.FileName.FullPath.ToString() = filename) - - let getOpenDocContent (filename: string) = - match getOpenDoc filename with - | Some d -> - match d.Editor with - | null -> None - | editor -> - let bytes = System.Text.Encoding.UTF8.GetBytes (editor.Text) - Some bytes - | _ -> None - static member IsAScript fileName = let ext = Path.GetExtension fileName [".fsx";".fsscript";".sketchfs"] |> List.exists ((=) ext) - //interface IFileSystem with - //member x.FileStreamReadShim fileName = - // getOpenDocContent fileName - // |> Option.map (fun bytes -> new MemoryStream (bytes) :> Stream) - // |> Option.orElse (fun () -> defaultFileSystem.FileStreamReadShim fileName) - - //member x.ReadAllBytesShim fileName = - // getOpenDocContent fileName - // |> Option.getOrElse (fun () -> defaultFileSystem.ReadAllBytesShim fileName) - - //member x.GetLastWriteTimeShim fileName = defaultFileSystem.GetLastWriteTimeShim(fileName) - // //let r = maybe { - // // let! doc = getOpenDoc fileName - // // if doc.IsDirty then - // // let key, newhash = fileName, doc.Editor.Text.GetHashCode() - // // return match timestamps.TryGetValue (key) with - // // | true, (hash, date) when hash = newhash -> date - // // | _ -> let d = System.DateTime.Now - // // timestamps.[key] <- (newhash,d) - // // d - // // else return! None - // // } - // //r |> Option.getOrElse (fun () -> defaultFileSystem.GetLastWriteTimeShim fileName) - - //member x.GetTempPathShim() = defaultFileSystem.GetTempPathShim() - //member x.FileStreamCreateShim fileName = defaultFileSystem.FileStreamCreateShim fileName - //member x.FileStreamWriteExistingShim fileName = defaultFileSystem.FileStreamWriteExistingShim fileName - //member x.GetFullPathShim fileName = defaultFileSystem.GetFullPathShim fileName - //member x.IsInvalidPathShim fileName = defaultFileSystem.IsInvalidPathShim fileName - //member x.IsPathRootedShim fileName = defaultFileSystem.IsPathRootedShim fileName - //member x.SafeExists fileName = defaultFileSystem.SafeExists fileName - //member x.FileDelete fileName = defaultFileSystem.FileDelete fileName - //member x.AssemblyLoadFrom fileName = defaultFileSystem.AssemblyLoadFrom fileName - //member x.AssemblyLoad(assemblyName) = defaultFileSystem.AssemblyLoad assemblyName - //member x.IsStableFileHeuristic _fileName = true - module FileService = let supportedFileExtensions = set [".fsscript"; ".fs"; ".fsx"; ".fsi"; ".sketchfs"] diff --git a/vsintegration/src/FSharp.Editor/Common/LanguageService.fs b/vsintegration/src/FSharp.Editor/Common/LanguageService.fs index f370517a8ab..bca0d71fc29 100644 --- a/vsintegration/src/FSharp.Editor/Common/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/Common/LanguageService.fs @@ -33,153 +33,6 @@ module ServiceSettings = let maximumTimeout = getEnvInteger "FSharpBinding_MaxTimeout" 10000 let idleBackgroundCheckTime = getEnvInteger "FSharpBinding_IdleBackgroundCheckTime" 2000 -// -------------------------------------------------------------------------------------- -/// Wraps the result of type-checking and provides methods for implementing -/// various IntelliSense functions (such as completion & tool tips). -/// Provides default empty/negative results if information is missing. -//type ParseAndCheckResults (infoOpt : FSharpCheckFileResults option, parseResults : FSharpParseFileResults option) = - - ///// Get the symbols for declarations at the current location in the specified document and the long ident residue - ///// e.g. The incomplete ident One.Two.Th will return Th - //member x.GetDeclarationSymbols(line, col, lineStr) = - // async { - // match infoOpt, parseResults with - // | Some checkResults, parseResults -> - // // Get items & generate output - // let partialName = QuickParse.GetPartialLongNameEx(lineStr, col-1) - - // try - // let! results = checkResults.GetDeclarationListSymbols(parseResults, line, lineStr, partialName) - - // return Some (results, partialName.PartialIdent) - // with :? TimeoutException -> return None - // | None, _ -> return None - // } - - /////// Get the tool-tip to be displayed at the specified offset (relatively - /////// from the beginning of the current document) - ////member x.GetToolTip(line, col, lineStr) = - //// async { - //// match infoOpt with - //// | Some checkResults -> - //// match MonoDevelop.FSharp.Shared.Parsing.findIdents col lineStr MonoDevelop.FSharp.Shared.SymbolLookupKind.ByLongIdent with - //// | None -> return None - //// | Some(col,identIsland) -> - //// let! res = checkResults.GetToolTipText(line, col, lineStr, identIsland, FSharpTokenTag.Identifier) - //// return Some (res, line) - //// | None -> return None } - - ////member x.GetDeclarationLocation(line, col, lineStr) = - // //async { - // //match infoOpt with - // //| Some checkResults -> - // // match MonoDevelop.FSharp.Shared.Parsing.findIdents col lineStr MonoDevelop.FSharp.Shared.SymbolLookupKind.ByLongIdent with - // // | None -> return FSharpFindDeclResult.DeclNotFound (FSharpFindDeclFailureReason.Unknown "No idents found") - // // | Some(col,identIsland) -> return! checkResults.GetDeclarationLocation(line, col, lineStr, identIsland, false) - // //| None -> return FSharpFindDeclResult.DeclNotFound (FSharpFindDeclFailureReason.Unknown "No check results")} - - ////member x.GetSymbolAtLocation(line, col, lineStr) = - // //async { - // //match infoOpt with - // //| Some (checkResults) -> - // // match MonoDevelop.FSharp.Shared.Parsing.findIdents col lineStr MonoDevelop.FSharp.Shared.SymbolLookupKind.ByLongIdent - // // |> Option.orTry (fun () -> MonoDevelop.FSharp.Shared.Parsing.findIdents col lineStr MonoDevelop.FSharp.Shared.SymbolLookupKind.Fuzzy) with - // // | None -> return None - // // | Some(colu, identIsland) -> - // // try - // // let! symbolUse = checkResults.GetSymbolUseAtLocation(line, colu, lineStr, identIsland) - // // return symbolUse - // // with ex -> - // // LoggingService.LogDebug("Error at: GetSymbolUseAtLocation}", ex) - // // return None - // //| None -> return None } - - ////member x.GetMethodsAsSymbols(line, col, (lineStr:string)) = - // //async { - // //match infoOpt with - // //| Some checkResults -> - // // let lineToCaret = lineStr.[0..col-1] - // // let column = lineToCaret |> Seq.tryFindIndexBack (fun c -> c <> '(' && c <> ' ') - // // match column with - // // | Some col -> - // // match MonoDevelop.FSharp.Shared.Parsing.findIdents (col-1) lineToCaret MonoDevelop.FSharp.Shared.SymbolLookupKind.ByLongIdent with - // // | None -> return None - // // | Some(colu, identIsland) -> - // // return! checkResults.GetMethodsAsSymbols(line, colu, lineToCaret, identIsland) - // // | _ -> return None - // //| None -> return None } - - //member x.GetUsesOfSymbolInFile(symbol) = - // async { - // match infoOpt with - // | Some checkResults -> return! checkResults.GetUsesOfSymbolInFile(symbol) - // | None -> return [| |] } - - //member x.GetAllUsesOfAllSymbolsInFile() = - // async { - // match infoOpt with - // | Some checkResults -> - // let! allSymbols = checkResults.GetAllUsesOfAllSymbolsInFile() - // return Some allSymbols - // | None -> return None } - - //member x.PartialAssemblySignature = - // async { - // match infoOpt with - // | Some (checkResults) -> - // return Some checkResults.PartialAssemblySignature - // | None -> return None } - - //member x.GetErrors() = - // match infoOpt, parseResults with - // | Some checkResults, Some parseResults -> - // checkResults.Errors - // |> Array.append parseResults.Errors - // |> Seq.distinct - // | Some checkResults, None -> checkResults.Errors |> Array.toSeq - // | None, Some parseResults -> parseResults.Errors |> Array.toSeq - // | None, None -> Seq.empty - - //member x.GetNavigationItems() = - // match parseResults with - // | None -> [| |] - // | Some parseResults -> - // // GetNavigationItems is not 100% solid and throws occasional exceptions - // try parseResults.GetNavigationItems().Declarations - // with _ -> - // Debug.Assert(false, "couldn't update navigation items, ignoring") - // [| |] - - //member x.ParseTree = - // match parseResults with - // | Some parseResults -> parseResults.ParseTree - // | None -> None - - //member x.CheckResults = infoOpt - - //member x.GetExtraColorizations(range) = - // match infoOpt with - // | Some checkResults -> Some(checkResults.GetSemanticClassification(range)) - // | None -> None - - //member x.GetStringFormatterColours() = - // match infoOpt with - // | Some checkResults -> Some(checkResults.GetFormatSpecifierLocationsAndArity()) - // | None -> None - - ///// Get all the uses of a symbol in the given file - //member x.GetUsesOfSymbolAtLocationInFile(fileName, line, col, lineStr) = - //asyncMaybe { - // LoggingService.logDebug "LanguageService: GetUsesOfSymbolAtLocationInFile: file:%s, line:%i, col:%i" (Path.GetFileName(fileName)) line col - // let! colu, identIsland = MonoDevelop.FSharp.Shared.Parsing.findIdents col lineStr MonoDevelop.FSharp.Shared.SymbolLookupKind.ByLongIdent |> async.Return - // let! results = infoOpt |> async.Return - // let! symbolUse = results.GetSymbolUseAtLocation(line, colu, lineStr, identIsland) - // let! symbolUse = x.GetSymbolAtLocation(line, col, lineStr) - // let lastIdent = Seq.last identIsland - // let! refs = results.GetUsesOfSymbolInFile(symbolUse.Symbol) |> Async.map Some - // return (lastIdent, refs) - //} - [] type AllowStaleResults = // Allow checker results where the source doesn't even match @@ -198,44 +51,6 @@ type LanguageService(checker: FSharpChecker, dirtyNotify, _extraProjectInfo) as let fakeDateTimeRepresentingTimeLoaded proj = DateTime(abs (int64 (match proj with null -> 0 | _ -> proj.GetHashCode())) % 103231L) let checkProjectResultsCache = Collections.Generic.Dictionary() - //let projectChecked filename = - //let computation = - // async { - // let displayname = Path.GetFileName filename - // LoggingService.logDebug "LanguageService: Project checked: %s" displayname - // if checkProjectResultsCache.ContainsKey filename then - // LoggingService.logDebug "LanguageService: Removing project check results for: %s" displayname - // checkProjectResultsCache.Remove(filename) |> ignore - - // LoggingService.logDebug "LanguageService: Getting project checker options for: %s" displayname - // let projOptions = - // //if File.Exists filename then - // x.GetProjectCheckerOptions(filename) - // //else - // //let trimmedfilename = - // // let finaldot = filename.LastIndexOf "." - // // if finaldot > 0 then filename.[..finaldot-1] else "" - // //if not (String.IsNullOrWhiteSpace trimmedfilename) && File.Exists trimmedfilename then - // // let source = File.ReadAllText trimmedfilename - // // x.GetScriptCheckerOptions(filename, filename, source) - // //else - // //LoggingService.logDebug "LanguageService: Could not generate project options for: %s file does not exist" filename - // //None - // match projOptions with - // | Some projOptions -> - // LoggingService.logDebug "LanguageService: Getting CheckProjectResults for: %s" displayname - // try - // let! (projCheck:FSharpCheckProjectResults) = x.ParseAndCheckProject(projOptions) - // if not projCheck.HasCriticalErrors then - // LoggingService.logDebug "LanguageService: Adding CheckProjectResults to cache for: %s" displayname - // checkProjectResultsCache.Add(filename, projCheck) |> ignore - // else - // LoggingService.logDebug "LanguageService: NOT adding CheckProjectResults to cache for: %s due to critical errors" displayname - // with exn -> - // LoggingService.LogDebug(sprintf "LanguageService: Error", exn) - // | None -> () } - ////Async.StartAndLogException computation - //Async.Start computation let loadingProjects = HashSet() @@ -247,23 +62,6 @@ type LanguageService(checker: FSharpChecker, dirtyNotify, _extraProjectInfo) as if loadingProjects.Remove projectFileName then IdeApp.TypeSystemService.EndWorkspaceLoad() - // Create an instance of interactive checker. The callback is called by the F# compiler service - // when its view of the prior-typechecking-state of the start of a file has changed, for example - // when the background typechecker has "caught up" after some other file has been changed, - // and its time to re-typecheck the current file. -// let checker = -// let checker = FSharpChecker.Create() -// checker.PauseBeforeBackgroundWork <- ServiceSettings.idleBackgroundCheckTime -// checker.BeforeBackgroundFileCheck.Add dirtyNotify -//#if DEBUG -// checker.FileParsed.Add (fun (filename, _) -> LoggingService.logDebug "LanguageService: File parsed: %s" filename) -// checker.FileChecked.Add (fun (filename, _) -> LoggingService.logDebug "LanguageService: File type checked: %s" filename) -//#endif - //checker.ProjectChecked.Add (fun (filename, _) -> - // projectChecked filename - // hideStatusIcon filename) - //checker - /// When creating new script file on Mac, the filename we get sometimes /// has a name //foo.fsx, and as a result 'Path.GetFullPath' throws in the F# /// language service - this fixes the issue by inventing nicer file name. @@ -279,10 +77,6 @@ type LanguageService(checker: FSharpChecker, dirtyNotify, _extraProjectInfo) as Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%") Path.Combine(dir, Path.GetFileName(path)) - //let projectInfoCache = - ////cache 50 project infos, then start evicting the least recently used entries - //ref (ExtCore.Caching.LruCache.create 50u) - let optionsForDependentProject projectFile = let project = x.GetProjectFromFileName projectFile async { @@ -294,69 +88,13 @@ type LanguageService(checker: FSharpChecker, dirtyNotify, _extraProjectInfo) as return x.GetProjectCheckerOptions(projectFile, [], assemblies) } - //member x.Checker = checker - member x.HideStatusIcon = hideStatusIcon - //member x.ClearProjectInfoCache() = - //LoggingService.logDebug "LanguageService: Clearing ProjectInfoCache" - //projectInfoCache := ExtCore.Caching.LruCache.create 50u - - /// Constructs options for the interactive checker for the given file in the project under the given configuration. - //member x.GetCheckerOptions(fileName, projFilename, source) = - //let opts = - // if FileSystem.IsAScript fileName || fileName = projFilename - // // We are in a stand-alone file or we are in a project, but currently editing a script file - // then x.GetScriptCheckerOptions(fileName, projFilename, source) - // // We are in a project - construct options using current properties - // else x.GetProjectCheckerOptions(projFilename) - //opts - - //member x.GetParsingOptionsFromProjectOptions(projectOptions) = - // checker.GetParsingOptionsFromProjectOptions projectOptions - - ///// Constructs options for the interactive checker for the given script file in the project under the given configuration. - //member x.GetScriptCheckerOptions(fileName, projFilename, source) = - //let opts = - // // We are in a stand-alone file or we are in a project, but currently editing a script file - // try - // let fileName = fixFileName(fileName) - // LoggingService.LogDebug ("LanguageService: GetScriptCheckerOptions: Creating for stand-alone file or script: {0}", fileName) - // let opts, _errors = - // Async.RunSynchronously (checker.GetProjectOptionsFromScript(fileName, SourceText.ofString source, fakeDateTimeRepresentingTimeLoaded projFilename), - // timeout = ServiceSettings.maximumTimeout) - - // // The InteractiveChecker resolution sometimes doesn't include FSharp.Core and other essential assemblies, so we need to include them by hand - // if opts.OtherOptions |> Seq.exists (fun s -> s.Contains("FSharp.Core.dll")) then opts - // else - // // Add assemblies that may be missing in the standard assembly resolution - // LoggingService.LogDebug("LanguageService: GetScriptCheckerOptions: Adding missing core assemblies.") - // let dirs = FSharpEnvironment.getDefaultDirectories (None, FSharpTargetFramework.NET_4_5 ) - // { opts with OtherOptions = [| yield! opts.OtherOptions - // match FSharpEnvironment.resolveAssembly dirs "FSharp.Core" with - // | Some fn -> yield String.Format ("-r:{0}", fn) - // | None -> - // LoggingService.LogDebug("LanguageService: Resolution: FSharp.Core assembly resolution failed!") - // match FSharpEnvironment.resolveAssembly dirs "FSharp.Compiler.Interactive.Settings" with - // | Some fn -> yield String.Format ("-r:{0}", fn) - // | None -> LoggingService.LogDebug("LanguageService: Resolution: FSharp.Compiler.Interactive.Settings assembly resolution failed!") |]} - // with e -> failwithf "Exception when getting check options for '%s'\n.Details: %A" fileName e - - //// Print contents of check option for debugging purposes - //// LoggingService.LogDebug(sprintf "GetScriptCheckerOptions: ProjectFileName: %s, ProjectFileNames: %A, ProjectOptions: %A, IsIncompleteTypeCheckEnvironment: %A, UseScriptResolutionRules: %A" - //// opts.ProjectFileName opts.ProjectFileNames opts.ProjectOptions opts.IsIncompleteTypeCheckEnvironment opts.UseScriptResolutionRules) - //Some opts - member x.GetProjectFromFileName projectFile = IdeApp.Workspace.GetAllProjects() |> Seq.tryFind (fun p -> p.FileName.FullPath.ToString() = projectFile) |> Option.map(fun p -> p :?> DotNetProject) - //maybe { - // let! projConfig = proj.GetConfiguration(config) |> Option.tryCast - // let! fsconfig = projConfig.CompilationParameters |> Option.tryCast - // return generateProjectOptions (proj, referencedAssemblies, fsconfig, None, getTargetFramework projConfig.TargetFramework.Id, config, false) - //} member x.GetProjectOptionsFromProjectFile (project:DotNetProject) (config:ConfigurationSelector) (referencedAssemblies:AssemblyReference seq) = // hack: we can't just pull the refs out of referencedAssemblies as we use this for referenced projects as well @@ -383,12 +121,6 @@ type LanguageService(checker: FSharpChecker, dirtyNotify, _extraProjectInfo) as let _file, projectOptions = getOptions project projectOptions - //member x.TryGetProjectCheckerOptionsFromCache(projFilename, ?properties) : FSharpProjectOptions option = - //let properties = defaultArg properties ["Configuration", IdeApp.Workspace.ActiveConfigurationId] - //let key = (projFilename, properties) - //let entry, _ = (!projectInfoCache).TryFind (key) - //entry - /// Constructs options for the interactive checker for a project under the given configuration. member x.GetProjectCheckerOptions(projFilename, ?properties, ?referencedAssemblies) : FSharpProjectOptions option = let config = @@ -401,15 +133,6 @@ type LanguageService(checker: FSharpChecker, dirtyNotify, _extraProjectInfo) as | null -> null | ws -> ws.ActiveConfigurationId let properties = defaultArg properties ["Configuration", configId] - let key = (projFilename, properties) - - //lock projectInfoCache (fun () -> - //match (!projectInfoCache).TryFind (key) with - //| Some entry, cache -> - // LoggingService.logDebug "LanguageService: GetProjectCheckerOptions: Getting ProjectOptions from cache for:%s}" (Path.GetFileName(projFilename)) - // projectInfoCache := cache - // Some entry - //| _, cache -> showStatusIcon projFilename checker.ProjectChecked.Add (fun (filename, _) -> @@ -428,275 +151,8 @@ type LanguageService(checker: FSharpChecker, dirtyNotify, _extraProjectInfo) as | None -> (proj.GetReferences config).Result let opts = x.GetProjectOptionsFromProjectFile proj config asms opts |> Option.bind(fun opts' -> - //projectInfoCache := cache.Add (key, opts') // Print contents of check option for debugging purposes LoggingService.logDebug "GetProjectCheckerOptions: ProjectFileName: %s, ProjectFileNames: %A, ProjectOptions: %A, IsIncompleteTypeCheckEnvironment: %A, UseScriptResolutionRules: %A" opts'.ProjectFileName opts'.SourceFiles opts'.OtherOptions opts'.IsIncompleteTypeCheckEnvironment opts'.UseScriptResolutionRules opts) | None -> None - - //member x.StartBackgroundCompileOfProject (projectFilename) = - //x.GetProjectCheckerOptions(projectFilename) - //|> Option.iter(fun opts -> checker.CheckProjectInBackground(opts)) - - //member internal x.TryGetStaleTypedParseResult(fileName:string, options, src, stale) = - // // Try to get recent results from the F# service - // let res = - // match stale with - // | AllowStaleResults.MatchingFileName -> checker.TryGetRecentCheckResultsForFile(fixFileName fileName, options) - // | AllowStaleResults.MatchingSource -> checker.TryGetRecentCheckResultsForFile(fixFileName fileName, options, sourceText = SourceText.ofString src) - - // match res with - // | Some (untyped,typed,_) when typed.HasFullTypeCheckInfo -> Some (ParseAndCheckResults(Some typed, Some untyped)) - // | Some (untyped,_,_) -> Some (ParseAndCheckResults(None, Some untyped)) - // | _ -> None - - //member internal x.ParseAndCheckFile (fileName, src, version:int, options: FSharpProjectOptions option, obsoleteCheck) = - // async { - // try - // let fileName = fixFileName(fileName) - // match options with - // | Some opts -> - // let! parseResults, checkAnswer = checker.ParseAndCheckFileInProject(fileName, version, src ,opts, obsoleteCheck) - - // // Construct new typed parse result if the task succeeded - // let results = - // match checkAnswer with - // | FSharpCheckFileAnswer.Succeeded(checkResults) -> - // LoggingService.logDebug "LanguageService: ParseAndCheckFile check succeeded for %s" (Path.GetFileName(fileName)) - // ParseAndCheckResults(Some checkResults, Some parseResults) - // | FSharpCheckFileAnswer.Aborted -> - // LoggingService.logDebug "LanguageService: ParseAndCheckFile check aborted for %s" (Path.GetFileName(fileName)) - // ParseAndCheckResults(None, Some parseResults) - - // return results - // | None -> return ParseAndCheckResults(None, None) - // with exn -> - // LoggingService.LogDebug("LanguageService agent: Exception", exn) - // return ParseAndCheckResults(None, None) } - - //member x.ParseAndCheckFileInProject(projectFilename, fileName, version:int, src:string, obsoleteCheck) = - // let fileName = if Path.GetExtension fileName = ".sketchfs" then Path.ChangeExtension (fileName, ".fsx") else fileName - // let opts = x.GetCheckerOptions(fileName, projectFilename, src) - // x.ParseAndCheckFile(fileName, SourceText.ofString src, version, opts, obsoleteCheck) - - ///// Parses and checks the given file in the given project under the given configuration. - /////Asynchronously returns the results of checking the file. - //member x.GetTypedParseResultWithTimeout(projectFilename, fileName, version:int, src:string, stale, ?timeout, ?obsoleteCheck) = - //let obs = defaultArg obsoleteCheck (fun () -> false) - //async { - //let fileName = if Path.GetExtension fileName = ".sketchfs" then Path.ChangeExtension (fileName, ".fsx") else fileName - //let options = x.GetCheckerOptions(fileName, projectFilename, src) - //match options with - //| Some opts -> - // // Try to get recent results from the F# service - // match x.TryGetStaleTypedParseResult(fileName, opts, src, stale) with - // | Some _ as results -> - // LoggingService.logDebug "LanguageService: GetTypedParseResultWithTimeout: using stale results" - // return results - // | None -> - // // If we didn't get a recent set of type checking results, we put in a request and wait for at most 'timeout' for a response - // match timeout with - // | Some timeout -> - // LoggingService.logDebug "LanguageService: GetTypedParseResultWithTimeout: No stale results - typechecking with timeout" - // let! computation = Async.StartChild(x.ParseAndCheckFile(fileName, SourceText.ofString src, version, options, obs), timeout) - // try - // let! result = computation - // return Some(result) - // with - // | :? System.TimeoutException -> - // LoggingService.logDebug "LanguageService: GetTypedParseResultWithTimeout: No stale results - typechecking with timeout - timeout exception occurred" - // return None - // | None -> - // LoggingService.logDebug "LanguageService: GetTypedParseResultWithTimeout: No stale results - typechecking without timeout" - // let! result = x.ParseAndCheckFile(fileName, SourceText.ofString src, version, options, obs) - // return Some(result) - //| None -> return None } - - ///// Returns a TypeParsedResults if available, otherwise None - //member x.GetTypedParseResultIfAvailable(projectFilename, fileName:string, src, stale) = - // let options = x.GetCheckerOptions(fileName, projectFilename, src) - // LoggingService.logDebug "LanguageService: GetTypedParseResultIfAvailable: file=%s" (Path.GetFileName(fileName)) - // options |> Option.bind(fun opts -> x.TryGetStaleTypedParseResult(fileName, opts, src, stale)) - - //member x.GetSymbolAtLocationInFile(projectFilename, fileName, version, source, line:int, col, lineStr) = - // asyncMaybe { - // LoggingService.logDebug "LanguageService: GetUsesOfSymbolAtLocationInFile: file:%s, line:%i, col:%i" (Path.GetFileName(fileName)) line col - // let! _colu, identIsland = MonoDevelop.FSharp.Shared.Parsing.findIdents col lineStr MonoDevelop.FSharp.Shared.SymbolLookupKind.ByLongIdent |> async.Return - // let! results = x.GetTypedParseResultWithTimeout(projectFilename, fileName, version, source, AllowStaleResults.MatchingSource) - // let! symbolUse = results.GetSymbolAtLocation(line, col, lineStr) - // let lastIdent = Seq.last identIsland - // return (lastIdent, symbolUse) } - - ///// Get all the uses of the specified symbol in the current project and optionally all dependent projects - //member x.GetUsesOfSymbolInProject(projectFilename, file, source, symbol:FSharpSymbol, ?dependentProjects) = - //async { - // LoggingService.logDebug "LanguageService: GetUsesOfSymbolInProject: project:%s, currentFile:%s, symbol:%s" projectFilename file symbol.DisplayName - // let sourceProjectOptions = x.GetCheckerOptions(file, projectFilename, source) - - // let! dependentProjectsOptions = - // defaultArg dependentProjects [] - // |> Async.List.map optionsForDependentProject - - // let! allProjectResults = - // sourceProjectOptions :: dependentProjectsOptions - // |> List.choose id - // |> Async.List.map checker.ParseAndCheckProject - - // let! allSymbolUses = - // allProjectResults - // |> List.map (fun checkedProj -> checkedProj.GetUsesOfSymbol(symbol)) - // |> Async.Parallel - // |> Async.map Array.concat - - // return allSymbolUses - //} - - //member x.MatchingBraces(filename, projectFilename, source) = - //let options = x.GetCheckerOptions(filename, projectFilename, source) - //match options with - //| Some opts -> - // let parseOptions, _errors = x.GetParsingOptionsFromProjectOptions opts - // checker.MatchBraces(filename, SourceText.ofString source, parseOptions) - //| None -> async { return [||] } - - /// Get all symbols derived from the specified symbol in the current project and optionally all dependent projects - //member x.GetDerivedSymbolsInProject(projectFilename, file, source, symbolAtCaret:FSharpSymbol, ?dependentProjects) = - // LoggingService.logDebug "Finding derived symbols in %s : Symbol %s" projectFilename symbolAtCaret.DisplayName - // let predicate (symbolUse: FSharpSymbolUse) = - // try - // match symbolAtCaret with - // | :? FSharpMemberOrFunctionOrValue as caretmfv -> - // match symbolUse.Symbol with - // | :? FSharpMemberOrFunctionOrValue as mfv -> - // let isOverrideOrDefault = mfv.IsOverrideOrExplicitInterfaceImplementation - // let baseTypeMatch() = - // maybe { - // let! ent = mfv.DeclaringEntity - // let! bt = ent.BaseType - // let! carentEncEnt = caretmfv.DeclaringEntity - // return carentEncEnt.IsEffectivelySameAs bt.TypeDefinition } - - // let nameMatch = mfv.DisplayName = caretmfv.DisplayName - // let parameterMatch() = - // let both = (mfv.CurriedParameterGroups |> Seq.concat) |> Seq.zip (caretmfv.CurriedParameterGroups |> Seq.concat) - // let allMatch = both |> Seq.forall (fun (one, two) -> one.Type = two.Type) - // allMatch - // let allmatch = nameMatch && isOverrideOrDefault && baseTypeMatch().IsSome && parameterMatch() - // allmatch - // | _ -> false - // | :? FSharpEntity as ent -> - // match symbolUse.Symbol with - // | :? FSharpEntity as fse -> - // match fse.BaseType with - // | Some basetype -> - // basetype.TypeDefinition.IsEffectivelySameAs ent - // | _ -> false - // | _ -> false - // | _ -> false - // with ex -> - // false - - // async { - // LoggingService.logDebug "LanguageService: GetDerivedSymbolInProject: proj:%s, file:%s, symbol:%s" projectFilename file symbolAtCaret.DisplayName - // let sourceProjectOptions = x.GetCheckerOptions(file, projectFilename, source) - - // let! dependentProjectsOptions = - // defaultArg dependentProjects [] - // |> Async.List.map optionsForDependentProject - - // let! allProjectResults = - // sourceProjectOptions :: dependentProjectsOptions - // |> List.choose id - // |> Async.List.map checker.ParseAndCheckProject - - // let! allSymbolUses = - // allProjectResults - // |> List.map (fun checkedProj -> checkedProj.GetAllUsesOfAllSymbols()) - // |> Async.Parallel - // |> Async.map Array.concat - - // let filteredSymbols = allSymbolUses |> Array.filter predicate - - // return filteredSymbols } - - ///// Get all overloads derived from the specified symbol in the current project - ////Currently there seems to be an issue in FCS where a methods EnclosingEntity returns the wrong type - ////The sanest option is to just use the OverloadsProperty for now. - //member x.GetOverridesForSymbol(symbolAtCaret:FSharpSymbol) = - // try - // match symbolAtCaret with - // | :? FSharpMemberOrFunctionOrValue as caretmfv -> - // caretmfv.Overloads(false) - // | _ -> None - // with _ -> None - - //member x.GetExtensionMethods(projectFilename, file, source, symbolAtCaret:FSharpSymbol, ?dependentProjects) = - - // let isAnAttributedExtensionMethod (symbolToCompare:FSharpMemberOrFunctionOrValue) parentEntity = - // let hasExtension = symbolToCompare.Attributes |> Seq.tryFind (fun a -> a.AttributeType.DisplayName = "ExtensionAttribute") |> Option.isSome - // if hasExtension then - // let firstCurriedParamter = symbolToCompare.CurriedParameterGroups.[0].[0] - // let sameAs = firstCurriedParamter.Type.TypeDefinition.IsEffectivelySameAs parentEntity - // sameAs - // else false - - // let isAnExtensionMethod (mfv:FSharpMemberOrFunctionOrValue) (parentEntity:FSharpSymbol) = - // let isExt = mfv.IsExtensionMember - // let extslogicalEntity = mfv.ApparentEnclosingEntity - // let sameLogicalParent = parentEntity.IsEffectivelySameAs extslogicalEntity - // isExt && sameLogicalParent - - // let predicate (symbolUse: FSharpSymbolUse) = - // try - // match symbolAtCaret with - // | :? FSharpEntity as caretEntity -> - // match symbolUse.Symbol with - // | :? FSharpMemberOrFunctionOrValue as mfv -> - // isAnExtensionMethod mfv caretEntity || isAnAttributedExtensionMethod mfv caretEntity - // | _ -> false - // | _ -> false - // with ex -> - // false - - // async { - // LoggingService.logDebug "LanguageService: GetExtensionMethods: proj:%s, file:%s, symbol:%s" projectFilename file symbolAtCaret.DisplayName - // let sourceProjectOptions = x.GetCheckerOptions(file, projectFilename, source) - // let dependentProjectsOptions = defaultArg dependentProjects [] |> List.map x.GetProjectCheckerOptions - - // let! allProjectResults = - // sourceProjectOptions :: dependentProjectsOptions - // |> List.choose id - // |> Async.List.map checker.ParseAndCheckProject - - // let! allSymbolUses = - // allProjectResults - // |> List.map (fun checkedProj -> checkedProj.GetAllUsesOfAllSymbols()) - // |> Async.Parallel - // |> Async.map Array.concat - - // let filteredSymbols = allSymbolUses |> Array.filter predicate - // return filteredSymbols } - - //member x.ParseAndCheckProject options = - // checker.ParseAndCheckProject(options) - - //member x.GetCachedProjectCheckResult (project:Project) = - // //TODO clear cache on project invalidation - // //should we? Or just wait for the checker to finish which will update it anyway. - // match checkProjectResultsCache.TryGetValue (project.FileName.ToString()) with - // | true, v -> Some v - // | false, _ -> None - - ///// This function is called when the project is know to have changed for reasons not encoded in the ProjectOptions - ///// e.g. dependent references have changed - //member x.InvalidateConfiguration(options) = - // LoggingService.logDebug "LanguageService: Invalidating configuration for:%s" (Path.GetFileName(options.ProjectFileName)) - // checker.InvalidateConfiguration(options) - - ////flush all caches and garbage collect - //member x.ClearRootCaches() = - //LoggingService.logDebug "LanguageService: Clearing root caches and finalizing transients" - //checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() - //checkProjectResultsCache.Clear() - //x.ClearProjectInfoCache() diff --git a/vsintegration/src/FSharp.Editor/Common/Logger.fs b/vsintegration/src/FSharp.Editor/Common/Logger.fs index e325474210a..03a507bf74a 100644 --- a/vsintegration/src/FSharp.Editor/Common/Logger.fs +++ b/vsintegration/src/FSharp.Editor/Common/Logger.fs @@ -2,7 +2,6 @@ namespace Microsoft.VisualStudio.FSharp.Editor -open System open System open System.Diagnostics.Tracing diff --git a/vsintegration/src/FSharp.Editor/Common/MDLanguageService.fs b/vsintegration/src/FSharp.Editor/Common/MDLanguageService.fs deleted file mode 100644 index b710d394865..00000000000 --- a/vsintegration/src/FSharp.Editor/Common/MDLanguageService.fs +++ /dev/null @@ -1,173 +0,0 @@ -// -------------------------------------------------------------------------------------- -// Main file - contains types that call F# compiler service in the background, display -// error messages and expose various methods for to be used from MonoDevelop integration -// -------------------------------------------------------------------------------------- - -namespace MonoDevelop.FSharp -#nowarn "40" - -open System -open System.Collections.Generic -open System.Collections.Immutable -open System.Collections.ObjectModel -open System.IO -open System.Xml -open System.Text -open System.Diagnostics -//open ExtCore.Control -//open Mono.TextEditor -open MonoDevelop.Ide -open MonoDevelop.Ide.Editor -open MonoDevelop.Core -open MonoDevelop.Projects -open FSharp.Compiler.SourceCodeServices -open FSharp.Compiler.AbstractIL.Internal.Library -open MonoDevelop.Ide.TypeSystem - -module MonoDevelop = - - type TextEditor with - member x.GetLineInfoFromOffset (offset) = - let loc = x.OffsetToLocation(offset) - let line, col = max loc.Line 1, loc.Column - 1 - let currentLine = x.GetLineByOffset(offset) - let lineStr = x.Text.Substring(currentLine.Offset, currentLine.EndOffset - currentLine.Offset) - line, col, lineStr - - member x.GetLineInfoByCaretOffset () = - x.GetLineInfoFromOffset x.CaretOffset - - let inline private (>>=) a b = Option.bind b a - let inline private (!) a = Option.ofNull a - - type TypeSystem.ParsedDocument with - member x.TryGetAst() = - match x.Ast with - | null -> None - | :? ParseAndCheckResults as ast - -> Some ast - | _ -> None - - type DocumentContext with - member x.TryGetParsedDocument() = - !x >>=(fun pd -> !pd.ParsedDocument) - - member x.TryGetAst() = - x.TryGetParsedDocument() >>= (fun pd -> pd.TryGetAst()) - - member x.TryGetCheckResults() = - x.TryGetAst() >>= (fun ast -> ast.CheckResults) - - let internal getConfig () = - match IdeApp.Workspace with - | null -> ConfigurationSelector.Default - | ws -> - match ws.ActiveConfiguration with - | null -> ConfigurationSelector.Default - | config -> config - - - let visibleDocuments() = - IdeApp.Workbench.Documents - |> Seq.filter (fun doc -> match doc.Window with - | :? Gtk.Widget as w -> w.HasScreen - | _ -> false ) - - let isDocumentVisible filename = - visibleDocuments() - |> Seq.exists (fun d -> d.FileName = filename) - - let tryGetVisibleDocument filename = - visibleDocuments() - |> Seq.tryFind (fun d -> d.FileName = filename) - - -/// Provides functionality for working with the F# interactive checker running in background -type MDLanguageService() = - /// Single instance of the language service. We don't want the VFS during tests, so set it to blank from tests - /// before Instance is evaluated - static let mutable vfs = - lazy (let originalFs = Shim.FileSystem - let fs = new FileSystem(originalFs, (fun () -> seq { yield! match IdeApp.Workbench with - | null -> Seq.empty.ToImmutableList() - | _ -> IdeApp.Workbench.Documents })) - Shim.FileSystem <- fs - fs :> IFileSystem) - - static let mutable instance = - lazy - let _ = vfs.Force() - // VisualFSharp sets extraProjectInfo to be the Roslyn Workspace - // object, but we don't have that level of integration yet - let extraProjectInfo = None - new LanguageService( - (fun (changedfile, _) -> - try - let doc = IdeApp.Workbench.ActiveDocument - if doc <> null && doc.FileName.FullPath.ToString() = changedfile then - LoggingService.logDebug "FSharp Language Service: Compiler notifying document '%s' is dirty and needs reparsing. Reparsing as its the active document." (Path.GetFileName changedfile) - with exn -> - LoggingService.logDebug "FSharp Language Service: Error while attempting to notify document '%s' needs reparsing\n%s" (Path.GetFileName changedfile) (exn.ToString()) ), extraProjectInfo) - - static member Instance with get () = instance.Force () - and set v = instance <- lazy v - // Call this before Instance is called - static member DisableVirtualFileSystem() = - vfs <- lazy (Shim.FileSystem) - - static member invalidateProjectFile(projectFile: FilePath) = - try - if File.Exists (projectFile.FullPath.ToString()) then - MDLanguageService.Instance.TryGetProjectCheckerOptionsFromCache(projectFile.FullPath.ToString(), [("Configuration", IdeApp.Workspace.ActiveConfigurationId)]) - |> Option.iter(fun options -> - MDLanguageService.Instance.InvalidateConfiguration(options) - MDLanguageService.Instance.ClearProjectInfoCache()) - with ex -> LoggingService.LogError ("Could not invalidate configuration", ex) - - static member invalidateFiles (args:#ProjectFileEventInfo seq) = - for projectFileEvent in args do - if FileService.supportedFilePath projectFileEvent.ProjectFile.FilePath then - MDLanguageService.invalidateProjectFile(projectFileEvent.ProjectFile.FilePath) -[] -module MDLanguageServiceImpl = - let languageService = MDLanguageService.Instance - -/// Various utilities for working with F# language service -module internal ServiceUtils = - /// Translates icon code that we get from F# language service into a MonoDevelop icon - let getIcon (navItem: FSharpNavigationDeclarationItem) = - match navItem.Kind with - | NamespaceDecl -> "md-name-space" - | _ -> - match navItem.Glyph with - | FSharpGlyph.Class -> "md-class" - | FSharpGlyph.Enum -> "md-enum" - | FSharpGlyph.Struct -> "md-struct" - | FSharpGlyph.ExtensionMethod -> "md-struct" - | FSharpGlyph.Delegate -> "md-delegate" - | FSharpGlyph.Interface -> "md-interface" - | FSharpGlyph.Module -> "md-module" - | FSharpGlyph.NameSpace -> "md-name-space" - | FSharpGlyph.Method -> "md-method"; - | FSharpGlyph.OverridenMethod -> "md-method"; - | FSharpGlyph.Property -> "md-property" - | FSharpGlyph.Event -> "md-event" - | FSharpGlyph.Constant -> "md-field" - | FSharpGlyph.EnumMember -> "md-field" - | FSharpGlyph.Exception -> "md-exception" - | FSharpGlyph.Typedef -> "md-class" - | FSharpGlyph.Type -> "md-type" - | FSharpGlyph.Union -> "md-type" - | FSharpGlyph.Variable -> "md-field" - | FSharpGlyph.Field -> "md-field" - | FSharpGlyph.Error -> "md-breakpint" - -module internal KeywordList = - let modifiers = - dict [ - "abstract", """Indicates a method that either has no implementation in the type in which it is declared or that is virtual and has a default implementation.""" - "inline", """Used to indicate a function that should be integrated directly into the caller's code.""" - "mutable", """Used to declare a variable, that is, a value that can be changed.""" - "private", """Restricts access to a member to code in the same type or module.""" - "public", """Allows access to a member from outside the type.""" - ] diff --git a/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManagerProvider.fs b/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManagerProvider.fs deleted file mode 100644 index f641bb1edbb..00000000000 --- a/vsintegration/src/FSharp.Editor/Completion/AsyncCompletionCommitManagerProvider.fs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. - -namespace Microsoft.VisualStudio.FSharp.Editor.GRRRRR - -open System.Composition -open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion -open Microsoft.VisualStudio.Utilities -open Microsoft.VisualStudio.FSharp.Editor -open Microsoft.VisualStudio.Text.Editor - -[)>] -[] -[] -//[] -//[] -type FSharpAsyncCompletionCommitManagerProvider() = - //[] - //() = - let x = 1 - interface IAsyncCompletionCommitManagerProvider with - member __.GetOrCreate(textView) = - System.Diagnostics.Trace.Write("Hello") - System.Diagnostics.Trace.WriteLine("GetOrCreate FSharpAsyncCompletionCommitManager") - FSharpAsyncCompletionCommitManager() :> _ \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index 99f72e5bc88..545bd6b637e 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -10,19 +10,13 @@ open System.Threading.Tasks open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Completion -open Microsoft.CodeAnalysis.Options open Microsoft.CodeAnalysis.Text -open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion - -//open Microsoft.VisualStudio.Shell open FSharp.Compiler open FSharp.Compiler.Range open FSharp.Compiler.SourceCodeServices open Microsoft.VisualStudio.Text.Adornments -open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor -open Microsoft.CodeAnalysis.Editor.Shared.Extensions module Logger = Microsoft.VisualStudio.FSharp.Editor.Logger type internal FSharpCompletionProvider @@ -195,24 +189,13 @@ type internal FSharpCompletionProvider |> Option.bind (fun parseTree -> UntypedParseImpl.TryGetCompletionContext(Pos.fromZ caretLinePos.Line caretLinePos.Character, parseTree, lineStr)) - //let keywordGlyph = ExternalAccess.FSharp.FSharpGlyph.Keyword - //let k = Glyph.Keyword - //let roslynGlyph = Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.FSharpGlyphHelpers.ConvertTo(k) - //let i = ImageElement(roslynGlyph |> Gl GetImageId) let image = GlyphHelper.getImageId Glyph.Keyword |> ImageElement - //let c = - //FSharpCommonCompletionItem.Create(keyword, null, CompletionItemRules.Default, Nullable Glyph.Keyword ) - //.AddProperty("description", description) - //.AddProperty(IsKeywordPropName, "") + match completionContext with | None -> let keywordItemsWithSource = keywordCompletionItems |> Seq.mapi (fun n (keyword, description) -> - //FSharpCommonCompletionItem.Create(keyword, null, CompletionItemRules.Default, Nullable Glyph.Keyword ) - //.AddProperty("description", description) - //.AddProperty(IsKeywordPropName, "")) - let imageId = [ ] new Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem (keyword, completionSource, image, ImmutableArray.Empty, "", keyword, sprintf "%06d" (1000000 + n), keyword, keyword, ImmutableArray.Empty )) @@ -222,35 +205,8 @@ type internal FSharpCompletionProvider return results } - //override this.ShouldTriggerCompletion(sourceText: SourceText, caretPosition: int, trigger: CompletionTrigger, _: OptionSet) = - // use _logBlock = Logger.LogBlock LogEditorFunctionId.Completion_ShouldTrigger - - // let getInfo() = - // let documentId = workspace.GetDocumentIdInCurrentContext(sourceText.Container) - // let document = workspace.CurrentSolution.GetDocument(documentId) - // let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) - // (documentId, document.FilePath, defines) - - // FSharpCompletionProvider.ShouldTriggerCompletionAux(sourceText, caretPosition, trigger, getInfo, settings.IntelliSense) - override this.ProvideCompletionsAsync(context: Completion.CompletionContext) = asyncMaybe { - //use _logBlock = Logger.LogBlockMessage context.Document.Name LogEditorFunctionId.Completion_ProvideCompletionsAsync - - //let document = context.Document - //let! sourceText = context.Document.GetTextAsync(context.CancellationToken) - //let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) - //do! Option.guard (CompletionUtils.shouldProvideCompletion(document.Id, document.FilePath, defines, sourceText, context.Position)) - //let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken) - //let! textVersion = context.Document.GetTextVersionAsync(context.CancellationToken) - //let getAllSymbols(fileCheckResults: FSharpCheckFileResults) = - // if settings.IntelliSense.IncludeSymbolsFromUnopenedNamespacesOrModules - // then assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies(fileCheckResults) - // else [] - //let! results = - //FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, sourceText, context.Position, projectOptions, document.FilePath, - //textVersion.GetHashCode(), getAllSymbols, settings.LanguageServicePerformance, settings.IntelliSense) - context.AddItems([])//results) } |> Async.Ignore |> RoslynHelpers.StartAsyncUnitAsTask context.CancellationToken @@ -276,20 +232,14 @@ type internal FSharpCompletionProvider member this.GetDescriptionAsync2(textView: ITextView, completionItem: Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem, cancellationToken: CancellationToken): Task = async { - //use _logBlock = Logger.LogBlockMessage "DocumentName" ViewportWidthLogEditorFunctionId.Completion_GetDescriptionAsync match completionItem.Properties.TryGetProperty IndexPropName with | true, (declarationItem: FSharpDeclarationListItem) -> - //let completionItemIndex = int completionItemIndexStr - //if completionItemIndex < declarationItems.Length then - //let declarationItem = declarationItems.[completionItemIndex] - let! description = declarationItem.StructuredDescriptionTextAsync - let documentation = List() - let collector = RoslynHelpers.CollectTaggedText documentation - // mix main description and xmldoc by using one collector - XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, collector, collector, collector, description) - return CompletionDescription.Create(documentation.ToImmutableArray()) - //else - //return CompletionDescription.Empty + let! description = declarationItem.StructuredDescriptionTextAsync + let documentation = List() + let collector = RoslynHelpers.CollectTaggedText documentation + // mix main description and xmldoc by using one collector + XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, collector, collector, collector, description) + return CompletionDescription.Create(documentation.ToImmutableArray()) | _ -> return CompletionDescription.Empty } |> RoslynHelpers.StartAsyncAsTask cancellationToken diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index d09ea4d7bff..fdaa2cfd519 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -2,12 +2,10 @@ namespace Microsoft.VisualStudio.FSharp.Editor -open System.Composition open System.Collections.Immutable open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Completion -open Microsoft.CodeAnalysis.Host.Mef open Microsoft.CodeAnalysis.ExternalAccess.FSharp open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion @@ -36,7 +34,7 @@ type internal FSharpCompletionService let builtInProviders = ImmutableArray.Create( - FSharpCompletionProvider(workspace, (*serviceProvider,*) checkerProvider, projectInfoManager, assemblyContentProvider), + FSharpCompletionProvider(workspace, checkerProvider, projectInfoManager, assemblyContentProvider), FSharpCommonCompletionProvider.Create( HashDirectiveCompletionProvider(workspace, projectInfoManager, [ Completion.Create("""\s*#load\s+(@?"*(?"[^"]*"?))""", [".fs"; ".fsx"], useIncludeDirectives = true) @@ -61,8 +59,6 @@ type internal FSharpCompletionSource (textView: ITextView, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider) = - //let settings: EditorOptions = textView.TextBuffer.GetWorkspace().Services.GetService() - let createParagraphFromLines(lines: List) = if lines.Count = 1 then // The paragraph contains only one line, so it doesn't need to be added to a container. Avoiding the diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs index 581daaa1426..4ce504f6d47 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionUtils.fs @@ -112,34 +112,6 @@ module internal CompletionUtils = | CompletionItemKind.Other -> 6 | CompletionItemKind.Method (isExtension = true) -> 7 - - //public static TextSpan GetWordSpan(SourceText text, int position, - // Func isWordStartCharacter, Func isWordCharacter, bool alwaysExtendEndSpan = false) - //{ - // var start = position; - // while (start > 0 && isWordStartCharacter(text[start - 1])) - // { - // start--; - // } - - // // If we're brought up in the middle of a word, extend to the end of the word as well. - // // This means that if a user brings up the completion list at the start of the word they - // // will "insert" the text before what's already there (useful for qualifying existing - // // text). However, if they bring up completion in the "middle" of a word, then they will - // // "overwrite" the text. Useful for correcting misspellings or just replacing unwanted - // // code with new code. - // var end = position; - // if (start != position || alwaysExtendEndSpan) - // { - // while (end < text.Length && isWordCharacter(text[end])) - // { - // end++; - // } - // } - - // return TextSpan.FromBounds(start, end); - //} - let getCompletionItemSpan (sourceText: SourceText) position = let rec findStart index = let c = sourceText.[index-1] diff --git a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs index 5ae030b1e51..7a8f22262e4 100644 --- a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs +++ b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs @@ -2,19 +2,13 @@ namespace Microsoft.VisualStudio.FSharp.Editor -open System open System.Composition open System.Collections.Generic open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.SignatureHelp open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.ExternalAccess.FSharp.SignatureHelp -open Microsoft.VisualStudio.Text -////open Microsoft.VisualStudio.Shell -//open Microsoft.VisualStudio.Shell.Interop - open FSharp.Compiler.Layout open FSharp.Compiler.Range open FSharp.Compiler.SourceCodeServices @@ -24,13 +18,12 @@ open FSharp.Compiler.SourceCodeServices type internal FSharpSignatureHelpProvider [] ( - //serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager ) = static let userOpName = "SignatureHelpProvider" - let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder((*serviceProvider.XMLMemberIndexService*)) + let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder() static let oneColAfter (lp: LinePosition) = LinePosition(lp.Line,lp.Character+1) static let oneColBefore (lp: LinePosition) = LinePosition(lp.Line,max 0 (lp.Character-1)) diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs index 37c61dff5b5..eb027c691cf 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs @@ -120,9 +120,6 @@ type internal FSharpDocumentDiagnosticAnalyzer [] () = interface IFSharpDocumentDiagnosticAnalyzer with member this.AnalyzeSyntaxAsync(document: Document, cancellationToken: CancellationToken): Task> = - //Task.FromResult ImmutableArray.Empty - // None of the analyzers appear to do syntax checking, only semantic checking - // and this function is causing a StackOverflow on Mono let projectInfoManager = getProjectInfoManager document asyncMaybe { let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs index 099e2c1a40f..d856f65b4e2 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs @@ -46,19 +46,6 @@ type internal UnusedOpensDiagnosticAnalyzer [] () = interface IFSharpUnusedOpensDiagnosticAnalyzer with member this.AnalyzeSemanticsAsync(descriptor, document: Document, cancellationToken: CancellationToken) = - - //TextViewFromDocument(Document document) - //{ - // return document?.GetContent(); - //} - - //private Document DocumentFromTextView(ITextView textView) - //{ - // return IdeApp.Workbench.Documents.FirstOrDefault(doc => TextViewFromDocument(doc) == textView); - //} - - //private Document DocumentFromTextBuffer(ITextBuffer textBuffer) - //{ let isOpen = MonoDevelop.Ide.IdeApp.Workbench.Documents |> Seq.exists(fun d -> d.FilePath |> string = document.FilePath) diff --git a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs index afe0fb03760..93f1b5867c4 100644 --- a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs +++ b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs @@ -5,8 +5,6 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System open System.Runtime.CompilerServices open System.Text.RegularExpressions -//open Microsoft.VisualStudio.Shell -//open Microsoft.VisualStudio.Shell.Interop open FSharp.Compiler.SourceCodeServices open FSharp.Compiler.Layout open FSharp.Compiler.Layout.TaggedTextOps @@ -314,34 +312,16 @@ module internal XmlDocumentation = new FileStream(xmlPath, FileMode.Open, FileAccess.Read) :> Stream override x.Equals(obj) = - if obj :? FSharpXmlDocumentationProvider then - (obj:?>FSharpXmlDocumentationProvider).XmlPath = xmlPath - else + match obj with + | :? FSharpXmlDocumentationProvider as provider -> + provider.XmlPath = xmlPath + | _ -> false override x.GetHashCode() = xmlPath.GetHashCode() /// Provide Xml Documentation - type Provider((*xmlIndexService:IVsXMLMemberIndexService*)) = - /// Index of assembly name to xml member index. - //let cache = Dictionary() - - //do Events.SolutionEvents.OnAfterCloseSolution.Add (fun _ -> cache.Clear()) - - /// Retrieve the pre-existing xml index or None - //let GetMemberIndexOfAssembly(assemblyName) = - //match cache.TryGetValue(assemblyName) with - //| true, memberIndex -> Some(memberIndex) - //| false, _ -> - //let ok,memberIndex = xmlIndexService.CreateXMLMemberIndex(assemblyName) - //if Com.Succeeded(ok) then - // let ok = memberIndex.BuildMemberIndex() - // if Com.Succeeded(ok) then - // cache.Add(assemblyName, memberIndex) - // Some(memberIndex) - // else None - //else None - + type Provider() = let AppendMemberData(xmlCollector: ITaggedTextCollector, exnCollector: ITaggedTextCollector, xmlDocReader: XmlDocReader, showExceptions, showParameters) = AppendHardLine xmlCollector xmlCollector.StartXMLDoc() @@ -380,14 +360,6 @@ module internal XmlDocumentation = paramName:string option ) = try - //match GetMemberIndexOfAssembly(filename) with - //| Some(index) -> - // let _,idx = index.ParseMemberSignature(signature) - // if idx <> 0u then - // let ok,xml = index.GetMemberXML(idx) - // if Com.Succeeded(ok) then - // (this:>IDocumentationBuilder).AppendDocumentationFromProcessedXML(xmlCollector, exnCollector, xml, showExceptions, showParameters, paramName) - //| None -> () (this:>IDocumentationBuilder).AppendDocumentationFromProcessedXML(xmlCollector, exnCollector, FSharpXmlDocumentationProvider(filename).GetDocumentation(signature), showExceptions, showParameters, paramName) with e-> Assert.Exception(e) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 1b76077b7f1..8f1dd952916 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -74,7 +74,6 @@ - @@ -91,7 +90,6 @@ - @@ -134,7 +132,6 @@ - @@ -151,7 +148,6 @@ - @@ -166,7 +162,6 @@ - @@ -176,7 +171,6 @@ - FSharp.Editor.resx diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index 0f5abd45d06..5d788827b5b 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -1,65 +1,63 @@  - - - - - - - - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - \ No newline at end of file + + diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs index fc5bef7af5b..8a47e756048 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs @@ -22,7 +22,6 @@ type internal FSharpCheckerProvider [] ( analyzerService: IFSharpDiagnosticAnalyzerService, - //[)>] workspace: VisualStudioWorkspace, settings: EditorOptions ) = let workspace = IdeApp.TypeSystemService.Workspace :?> MonoDevelopWorkspace diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs index 1c921c7afab..ebbe56199a6 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpContentType.fs @@ -3,8 +3,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal open System.ComponentModel.Composition open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor -//open Microsoft.VisualStudio.Utilities -open Microsoft.VisualStudio.Editor + type FSharpContentTypeDefinitions() = [] [] diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index c56598d855a..3e3944cb83f 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -14,45 +14,13 @@ open FSharp.Compiler.SourceCodeServices open Microsoft.VisualStudio open Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.LanguageServices -//open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem -//open Microsoft.VisualStudio.Shell open System.Threading -//open Microsoft.VisualStudio.Shell.Interop -//open Microsoft.VisualStudio.LanguageServices.Implementation.TaskList -//open Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices open MonoDevelop.FSharp open MonoDevelop.Ide open MonoDevelop.Ide.TypeSystem [] module private FSharpProjectOptionsHelpers = - - //let mapCpsProjectToSite(project:Project, cpsCommandLineOptions: IDictionary) = - // let sourcePaths, referencePaths, options = - // match cpsCommandLineOptions.TryGetValue(project.Id) with - // | true, (sourcePaths, options) -> sourcePaths, [||], options - // | false, _ -> [||], [||], [||] - // let mutable errorReporter = Unchecked.defaultof<_> - // { - // new IProjectSite with - // member __.Description = project.Name - // member __.CompilationSourceFiles = sourcePaths - // member __.CompilationOptions = - // Array.concat [options; referencePaths |> Array.map(fun r -> "-r:" + r)] - // member __.CompilationReferences = referencePaths - // member site.CompilationBinOutputPath = site.CompilationOptions |> Array.tryPick (fun s -> if s.StartsWith("-o:") then Some s.[3..] else None) - // 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 = None - // //member __.BuildErrorReporter with get () = errorReporter and set (v) = errorReporter <- v - // } - let hasProjectVersionChanged (oldProject: Project) (newProject: Project) = oldProject.Version <> newProject.Version @@ -83,7 +51,7 @@ type private FSharpProjectOptionsMessage = | ClearSingleFileOptionsCache of DocumentId [] -type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) settings: EditorOptions, (*_serviceProvider,*) checkerProvider: FSharpCheckerProvider) = +type private FSharpProjectOptionsReactor (settings: EditorOptions, checkerProvider: FSharpCheckerProvider) = let cancellationTokenSource = new CancellationTokenSource() // Hack to store command line options from HandleCommandLineChanges @@ -151,15 +119,6 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) return Some(parsingOptions, projectOptions) } - //let tryGetProjectSite (project: Project) = - //// Cps - //if cpsCommandLineOptions.ContainsKey project.Id then - // Some (mapCpsProjectToSite(project, cpsCommandLineOptions)) - //else - //// Legacy - //match legacyProjectSites.TryGetValue project.Id with - //| true, site -> Some site - //| _ -> None let mdLanguageService = new MonoDevelop.FSharp.LanguageService(checkerProvider.Checker, (fun (changedfile, _) -> ()), None) let rec tryComputeOptions (project: Project) = @@ -172,65 +131,14 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) // the command line options will not be available and we should bail if one of the project references does not give us anything. let mutable canBail = false - //let referencedProjects = ResizeArray() - - //if settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences then - //for projectReference in project.ProjectReferences do - //let referencedProject = project.Solution.GetProject(projectReference.ProjectId) - //if referencedProject.Language = FSharpConstants.FSharpLanguageName then - //match! tryComputeOptions referencedProject with - //| None -> canBail <- true - //| Some(_, projectOptions) -> referencedProjects.Add(referencedProject.OutputFilePath, projectOptions) - - - - //match tryGetProjectSite project with - //| None -> return None - //| Some projectSite -> let fsharpProject = MonoDevelop.Ide.IdeApp.TypeSystemService.GetMonoProject(project) :?> MonoDevelop.FSharp.FSharpProject let! refs = fsharpProject.GetReferences(MonoDevelop.FSharp.CompilerArguments.getConfig()) |> Async.AwaitTask canBail <- refs.Count = 0 if canBail then return None else - //MonoDevelop.FSharp.MDLanguageService.DisableVirtualFileSystem() let projectOpts = mdLanguageService.GetProjectCheckerOptions(project.FilePath, [], refs) - //let otherOptions = - // project.ProjectReferences - // |> Seq.map (fun x -> "-r:" + project.Solution.GetProject(x.ProjectId).OutputFilePath) - // |> Array.ofSeq - // |> Array.append ( - // project.MetadataReferences.OfType() - // |> Seq.map (fun x -> "-r:" + x.FilePath) - // |> Array.ofSeq - // |> Array.append ( - // // Clear any references from CompilationOptions. - // // We get the references from Project.ProjectReferences/Project.MetadataReferences. - // projectSite.CompilationOptions - // |> Array.filter (fun x -> not (x.Contains("-r:"))) - // ) - // ) - - //let projectOptions = - //{ - // ProjectFileName = projectSite.ProjectFileName - // ProjectId = Some(projectId.ToFSharpProjectIdString()) - // SourceFiles = projectSite.CompilationSourceFiles - // OtherOptions = otherOptions - // ReferencedProjects = referencedProjects.ToArray() - // IsIncompleteTypeCheckEnvironment = projectSite.IsIncompleteTypeCheckEnvironment - // UseScriptResolutionRules = SourceFile.MustBeSingleFileProject (Path.GetFileName(project.FilePath)) - // LoadTime = projectSite.LoadTime - // UnresolvedReferences = None - // OriginalLoadReferences = [] - // ExtraProjectInfo= None - // Stamp = Some(int64 (project.Version.GetHashCode())) - //} - - return projectOpts |> Option.bind(fun opts -> - //let sourceFiles = projectOptions.OtherOptions.Where(fun o -> o.StartsWith("/")) - //let projectOptions = { projectOptions with SourceFiles = sourceFiles.ToArray() } // This can happen if we didn't receive the callback from HandleCommandLineChanges yet. if Array.isEmpty opts.SourceFiles then None @@ -286,7 +194,6 @@ type private FSharpProjectOptionsReactor ((*_workspace: VisualStudioWorkspace,*) | FSharpProjectOptionsMessage.ClearOptions(projectId) -> cache.Remove(projectId) |> ignore - //legacyProjectSites.TryRemove(projectId) |> ignore | FSharpProjectOptionsMessage.ClearSingleFileOptionsCache(documentId) -> singleFileCache.Remove(documentId) |> ignore } @@ -332,16 +239,10 @@ type internal FSharpProjectOptionsManager [] ( checkerProvider: FSharpCheckerProvider, - //[)>] workspace: VisualStudioWorkspace, - //[)>] serviceProvider: System.IServiceProvider, settings: EditorOptions ) = - //let projectDisplayNameOf projectFileName = - //if String.IsNullOrWhiteSpace projectFileName then projectFileName - //else Path.GetFileNameWithoutExtension projectFileName - - let reactor = new FSharpProjectOptionsReactor(settings, (*serviceProvider,*) checkerProvider) + let reactor = new FSharpProjectOptionsReactor(settings, checkerProvider) do let workspace = IdeApp.TypeSystemService.Workspace @@ -394,27 +295,4 @@ type internal FSharpProjectOptionsManager return result |> Option.map(fun (parsingOptions, _, projectOptions) -> parsingOptions, projectOptions) } - //[] - ///// This handles commandline change notifications from the Dotnet Project-system - ///// Prior to VS 15.7 path contained path to project file, post 15.7 contains target binpath - ///// binpath is more accurate because a project file can have multiple in memory projects based on configuration - //member __.HandleCommandLineChanges(path:string, sources:ImmutableArray, _references:ImmutableArray, options:ImmutableArray) = - //use _logBlock = Logger.LogBlock(LogEditorFunctionId.LanguageService_HandleCommandLineArgs) - - //let projectId = - // match Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.TryGetProjectIdByBinPath(workspace, path) with - // | true, projectId -> projectId - // | false, _ -> Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetOrCreateProjectIdForPath(workspace, path, projectDisplayNameOf path) - //let path = Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetProjectFilePath(workspace, projectId) - - //let getFullPath p = - // let p' = - // if Path.IsPathRooted(p) || path = null then p - // else Path.Combine(Path.GetDirectoryName(path), p) - // Path.GetFullPathSafe(p') - - //let sourcePaths = sources |> Seq.map(fun s -> getFullPath s.Path) |> Seq.toArray - - //reactor.SetCpsCommandLineOptions(projectId, sourcePaths, options.ToArray()) - member __.Checker = checkerProvider.Checker diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 390003cc4da..aee0e406fa7 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -3,24 +3,10 @@ namespace rec Microsoft.VisualStudio.FSharp.Editor open System -open System.ComponentModel.Design -open System.Runtime.InteropServices -open System.Threading -open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Options open FSharp.Compiler.SourceCodeServices -open FSharp.NativeInterop open Microsoft.VisualStudio open Microsoft.VisualStudio.FSharp.Editor -//open Microsoft.VisualStudio.LanguageServices -//open Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService -//open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem -//open Microsoft.VisualStudio.LanguageServices.ProjectSystem -//open Microsoft.VisualStudio.Shell -//open Microsoft.VisualStudio.Shell.Interop -open Microsoft.VisualStudio.Text.Outlining -open FSharp.NativeInterop -open Microsoft.CodeAnalysis.ExternalAccess.FSharp #nowarn "9" // NativePtr.toNativeInt @@ -57,191 +43,9 @@ type internal FSharpCheckerWorkspaceServiceFactory member __.Checker = checkerProvider.Checker member __.FSharpProjectOptionsManager = projectInfoManager } -//[] -//type private FSharpSolutionEvents(projectManager: FSharpProjectOptionsManager) = - -// interface IVsSolutionEvents with - -// member __.OnAfterCloseSolution(_) = -// projectManager.Checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() -// VSConstants.S_OK - -// member __.OnAfterLoadProject(_, _) = VSConstants.E_NOTIMPL - -// member __.OnAfterOpenProject(_, _) = VSConstants.E_NOTIMPL - -// member __.OnAfterOpenSolution(_, _) = VSConstants.E_NOTIMPL - -// member __.OnBeforeCloseProject(_, _) = VSConstants.E_NOTIMPL - -// member __.OnBeforeCloseSolution(_) = VSConstants.E_NOTIMPL - -// member __.OnBeforeUnloadProject(_, _) = VSConstants.E_NOTIMPL - -// member __.OnQueryCloseProject(_, _, _) = VSConstants.E_NOTIMPL - -// member __.OnQueryCloseSolution(_, _) = VSConstants.E_NOTIMPL - -// member __.OnQueryUnloadProject(_, _) = VSConstants.E_NOTIMPL - [, Microsoft.CodeAnalysis.Host.Mef.ServiceLayer.Default)>] type internal FSharpSettingsFactory [] (settings: EditorOptions) = interface Microsoft.CodeAnalysis.Host.Mef.IWorkspaceServiceFactory with member __.CreateService(_) = upcast settings -//[] -////[, -//// "F# Tools", "F# Interactive", // category/sub-category on Tools>Options... -//// 6000s, 6001s, // resource id for localisation of the above -//// true)>] // true = supports automation -////[] // <-- resource ID for localised name -////[, -//// // The following should place the ToolWindow with the OutputWindow by default. -//// Orientation=ToolWindowOrientation.Bottom, -//// Style=VsDockStyle.Tabbed, -//// PositionX = 0, -//// PositionY = 0, -//// Width = 360, -//// Height = 120, -//// Window="34E76E81-EE4A-11D0-AE2E-00A0C90FFFC3")>] -////[, "F#", null, "IntelliSense", "6008")>] -////[, "F#", null, "QuickInfo", "6009")>] -////[, "F#", null, "Code Fixes", "6010")>] -////[, "F#", null, "Performance", "6011")>] -////[, "F#", null, "Advanced", "6012")>] -////[, "F#", null, "CodeLens", "6013")>] -////[, "F#", null, "Formatting", "6014")>] -////[] -////// 64 represents a hex number. It needs to be greater than 37 so the TextMate editor will not be chosen as higher priority. -//[, ".fs", 64)>] -////[, ".fsi", 64)>] -////[, ".fsscript", 64)>] -////[, ".fsx", 64)>] -////[, ".ml", 64)>] -////[, ".mli", 64)>] -////[, 101s, CommonPhysicalViewAttributes = Constants.FSharpEditorFactoryPhysicalViewAttributes)>] -//[, ".fs")>] -//[, ".fsi")>] -//[, ".fsx")>] -//[, ".fsscript")>] -//[, ".ml")>] -//[, ".mli")>] -//[] -//[, -// strLanguageName = FSharpConstants.FSharpLanguageName, -// languageResourceID = 100, -// MatchBraces = true, -// MatchBracesAtCaret = true, -// ShowCompletion = true, -// ShowMatchingBrace = true, -// ShowSmartIndent = true, -// EnableAsyncCompletion = true, -// QuickInfo = true, -// DefaultToInsertSpaces = true, -// CodeSense = true, -// DefaultToNonHotURLs = true, -// RequestStockColors = true, -// EnableCommenting = true, -// CodeSenseDelay = 100, -// ShowDropDownOptions = true)>] -//type internal FSharpPackage() as this = - //inherit AbstractPackage() - -// //let mutable vfsiToolWindow = Unchecked.defaultof -// //let GetToolWindowAsITestVFSI() = -// //if vfsiToolWindow = Unchecked.defaultof<_> then -// // vfsiToolWindow <- this.FindToolWindow(typeof, 0, true) :?> Microsoft.VisualStudio.FSharp.Interactive.FsiToolWindow -// //vfsiToolWindow :> Microsoft.VisualStudio.FSharp.Interactive.ITestVFSI - -// let mutable solutionEventsOpt = None - -// // FSI-LINKAGE-POINT: unsited init -// //do -// //Microsoft.VisualStudio.FSharp.Interactive.Hooks.fsiConsoleWindowPackageCtorUnsited (this :> Package) - -// override this.InitializeAsync(cancellationToken: CancellationToken, progress: IProgress) : Tasks.Task = -// // `base.` methods can't be called in the `async` builder, so we have to cache it -// let baseInitializeAsync = base.InitializeAsync(cancellationToken, progress) -// let task = -// async { -// do! baseInitializeAsync |> Async.AwaitTask - -// //let! commandService = this.GetServiceAsync(typeof) |> Async.AwaitTask // FSI-LINKAGE-POINT -// //let commandService = commandService :?> OleMenuCommandService -// let packageInit () = -// // FSI-LINKAGE-POINT: sited init -// //Microsoft.VisualStudio.FSharp.Interactive.Hooks.fsiConsoleWindowPackageInitalizeSited (this :> Package) commandService - -// // FSI-LINKAGE-POINT: private method GetDialogPage forces fsi options to be loaded -// //let _fsiPropertyPage = this.GetDialogPage(typeof) -// let projectInfoManager = this.ComponentModel.DefaultExportProvider.GetExport().Value -// let solution = this.GetServiceAsync(typeof).Result -// let solution = solution :?> IVsSolution -// let solutionEvents = FSharpSolutionEvents(projectInfoManager) -// let rdt = this.GetServiceAsync(typeof).Result -// let rdt = rdt :?> IVsRunningDocumentTable - -// solutionEventsOpt <- Some(solutionEvents) -// solution.AdviseSolutionEvents(solutionEvents) |> ignore - -// let projectContextFactory = this.ComponentModel.GetService() -// let workspace = this.ComponentModel.GetService() -// let miscFilesWorkspace = this.ComponentModel.GetService() -// let _singleFileWorkspaceMap = new SingleFileWorkspaceMap(workspace, miscFilesWorkspace, projectInfoManager, projectContextFactory, rdt) -// let _legacyProjectWorkspaceMap = new LegacyProjectWorkspaceMap(solution, projectInfoManager, projectContextFactory) -// () -// let awaiter = this.JoinableTaskFactory.SwitchToMainThreadAsync().GetAwaiter() -// if awaiter.IsCompleted then -// packageInit() // already on the UI thread -// else -// awaiter.OnCompleted(fun () -> packageInit()) - -// } |> Async.StartAsTask -// upcast task // convert Task to Task - -// override this.RoslynLanguageName = FSharpConstants.FSharpLanguageName -// override this.CreateWorkspace() = this.ComponentModel.GetService() -// override this.CreateLanguageService() = FSharpLanguageService(this) -// override this.CreateEditorFactories() = this.CreateEditorFactories()// seq { yield FSharpEditorFactory(this) :> IVsEditorFactory } -// override this.RegisterMiscellaneousFilesWorkspaceInformation(miscFilesWorkspace) = -// miscFilesWorkspace.RegisterLanguage(Guid(FSharpConstants.languageServiceGuidString), FSharpConstants.FSharpLanguageName, ".fsx") - -// //interface Microsoft.VisualStudio.FSharp.Interactive.ITestVFSI with -// //member this.SendTextInteraction(s:string) = -// // GetToolWindowAsITestVFSI().SendTextInteraction(s) -// //member this.GetMostRecentLines(n:int) : string[] = -// //GetToolWindowAsITestVFSI().GetMostRecentLines(n) - -//[] -//type internal FSharpLanguageService(package : FSharpPackage) = - ////inherit AbstractLanguageService(package) - - //member this.Initialize() = - // base.Initialize() - - // this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Completion.FSharpCompletionOptions.BlockForCompletionItems, FSharpConstants.FSharpLanguageName, false) - // this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Shared.Options.FSharpServiceFeatureOnOffOptions.ClosedFileDiagnostic, FSharpConstants.FSharpLanguageName, Nullable false) - - // let theme = package.ComponentModel.DefaultExportProvider.GetExport().Value - // theme.SetColors() - - //member __.ContentTypeName = FSharpConstants.FSharpContentTypeName - //member __.LanguageName = FSharpConstants.FSharpLanguageName - //member __.RoslynLanguageName = FSharpConstants.FSharpLanguageName - - //member __.LanguageServiceId = new Guid(FSharpConstants.languageServiceGuidString) - //member __.DebuggerLanguageId = DebuggerEnvironment.GetLanguageID() - - ////member __.CreateContext(_,_,_,_,_) = raise(System.NotImplementedException()) - - //member this.SetupNewTextView(textView) = - //base.SetupNewTextView(textView) - - //// Toggles outlining (or code folding) based on settings - //let outliningManagerService = this.Package.ComponentModel.GetService() - //let wpfTextView = this.EditorAdaptersFactoryService.GetWpfTextView(textView) - //let outliningManager = outliningManagerService.GetOutliningManager(wpfTextView) - //if not (isNull outliningManager) then - //let settings = this.Workspace.Services.GetService() - //outliningManager.Enabled <- settings.Advanced.IsOutliningEnabled From 295ab4839c36e26452cd42d693868dbe81b2ea8f Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 30 Apr 2020 11:47:14 +0100 Subject: [PATCH 090/101] Clean up --- .../Completion/CompletionProvider.fs | 4 - .../src/FSharp.Editor/FSharp.Editor.fsproj | 2 - .../LanguageService/IProjectSite.fs | 61 -------------- .../Navigation/FindUsagesService.fs | 39 --------- .../Navigation/GoToDefinition.fs | 25 +----- .../Navigation/GoToDefinitionService.fs | 83 +------------------ .../Navigation/NavigableSymbolsService.fs | 39 +-------- .../Navigation/NavigateToSearchService.fs | 6 -- .../Options/SettingsPersistence.fs | 2 +- .../src/FSharp.Editor/Properties/AddinInfo.fs | 1 - .../QuickInfo/QuickInfoProvider.fs | 8 +- .../src/FSharp.Editor/QuickInfo/Views.fs | 1 - .../WpfNagivableTextRunViewElementFactory.fs | 66 --------------- .../src/FSharp.Editor/VSMac/InteractivePad.fs | 47 ++++------- .../FSharp.Editor/VSMac/InteractiveSession.fs | 17 ---- .../src/FSharp.Editor/VSMac/SignatureHelp.fs | 3 - 16 files changed, 24 insertions(+), 380 deletions(-) delete mode 100644 vsintegration/src/FSharp.Editor/LanguageService/IProjectSite.fs delete mode 100644 vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index 545bd6b637e..2459a9b22d6 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -22,7 +22,6 @@ module Logger = Microsoft.VisualStudio.FSharp.Editor.Logger type internal FSharpCompletionProvider ( workspace: Workspace, - //serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider @@ -51,7 +50,6 @@ type internal FSharpCompletionProvider let settings: EditorOptions = workspace.Services.GetService() - //let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder(serviceProvider.XMLMemberIndexService) let documentationBuilder = XmlDocumentation.Provider() static let noCommitOnSpaceRules = // These are important. They make sure we don't _commit_ autocompletion when people don't expect them to. Some examples: @@ -149,8 +147,6 @@ type internal FSharpCompletionProvider let completionItem = let item = new Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem(name, completionSource, icon = image) - //FSharpCommonCompletionItem.Create(name, null, rules = getRules intellisenseOptions.ShowAfterCharIsTyped, glyph = Nullable glyph, filterText = filterText) - //.AddProperty(FullNamePropName, declarationItem.FullName) item.Properties.AddProperty(IndexPropName, declarationItem) item diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 8f1dd952916..352daed92f8 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -102,7 +102,6 @@ - @@ -157,7 +156,6 @@ - diff --git a/vsintegration/src/FSharp.Editor/LanguageService/IProjectSite.fs b/vsintegration/src/FSharp.Editor/LanguageService/IProjectSite.fs deleted file mode 100644 index 0d778521a15..00000000000 --- a/vsintegration/src/FSharp.Editor/LanguageService/IProjectSite.fs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. - -namespace Microsoft.VisualStudio.FSharp.Editor - -open System.Runtime.InteropServices - -/// Narrow abstraction over the project system. -type internal AdviseProjectSiteChanges = delegate of unit -> unit - -[] -type internal IProvideProjectSite = - abstract GetProjectSite : unit -> IProjectSite - -/// Represents known F#-specific information about a project. -and internal IProjectSite = - - /// List of files in the project. In the correct order. - abstract CompilationSourceFiles : string[] - - /// Flags that the compiler would need to understand how to compile. Includes '-r' - /// options but not source files - abstract CompilationOptions : string[] - - /// The normalized '-r:' assembly references, without the '-r:' - abstract CompilationReferences : string[] - - /// The '-o:' output bin path, without the '-o:' - abstract CompilationBinOutputPath : string option - - /// The name of the project file. - abstract ProjectFileName : string - - /// Register for notifications for when the above change - abstract AdviseProjectSiteChanges : callbackOwnerKey: string * AdviseProjectSiteChanges -> unit - - /// 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 Description : string - - /// The error list task reporter - //abstract BuildErrorReporter : Microsoft.VisualStudio.Shell.Interop.IVsLanguageServiceBuildErrorReporter2 option with get, set - - /// False type resolution errors are invalid. This occurs with orphaned source files. The prior - /// type checking state is unknown. In this case we don't want to squiggle the type checking files. - abstract IsIncompleteTypeCheckEnvironment : bool - - /// target framework moniker - abstract TargetFrameworkMoniker : string - - /// Project Guid - abstract ProjectGuid : string - - /// timestamp the site was last loaded - abstract LoadTime : System.DateTime - - abstract ProjectProvider : IProvideProjectSite option \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs index 736928712f5..0cf43dc2d44 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs @@ -2,9 +2,7 @@ namespace Microsoft.VisualStudio.FSharp.Editor -open System.Threading open System.Collections.Immutable -open System.Composition open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.ExternalAccess.FSharp @@ -13,25 +11,8 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.FindUsages open FSharp.Compiler.Range open FSharp.Compiler.SourceCodeServices -open System.Composition -open System.Threading -open System.Threading.Tasks -open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.Editor -open Microsoft.CodeAnalysis.Host.Mef -open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor - -open System -open System; open System.ComponentModel.Composition; -open Microsoft.CodeAnalysis.Editor.Shared.Extensions; -open Microsoft.CodeAnalysis.Notification; -open Microsoft.CodeAnalysis.Shared.Extensions; -open Microsoft.CodeAnalysis.Text; -open Microsoft.VisualStudio.Commanding; -open Microsoft.VisualStudio.Text; -open Microsoft.VisualStudio.Text.Editor.Commanding.Commands; [)>] type internal FSharpFindUsagesService @@ -152,23 +133,3 @@ type internal FSharpFindUsagesService member __.FindImplementationsAsync(document, position, context) = findReferencedSymbolsAsync(document, position, context, false, userOpName) |> RoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken) - - -//[)>] -//[] -//[] -//type internal FSharpFindReferencesCommandHandler - //[] - //( - // checkerProvider: FSharpCheckerProvider, - // projectInfoManager: FSharpProjectOptionsManager - //) = - - //let gtd = GoToDefinition(checkerProvider.Checker, projectInfoManager) - //let statusBar = StatusBar((*ServiceProvider.GlobalProvider.GetService()*)) - //interface ICommandHandler with - //member __.DisplayName = "FSharp Find References" - //member __.GetCommandState(_args) = - // CommandState.Available - //member __.ExecuteCommand(args, context) = - //true \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs index 0480df18dfc..073365a823d 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs @@ -16,8 +16,6 @@ open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.Navigation open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Navigation -//open Microsoft.VisualStudio.Shell.Interop - open FSharp.Compiler.Range open FSharp.Compiler.SourceCodeServices @@ -107,41 +105,22 @@ module private ExternalSymbol = | _ -> [] // TODO: Uncomment code when VS has a fix for updating the status bar. -type internal StatusBar((*statusBar: IVsStatusbar*)) = - //let mutable _searchIcon = int16 Microsoft.VisualStudio.Shell.Interop.Constants.SBAI_Find :> obj - +type internal StatusBar() = let clear() = MonoDevelop.Ide.IdeApp.Workbench.StatusBar.ShowReady() - // unfreeze the statusbar - //statusBar.FreezeOutput 0 |> ignore - //statusBar.Clear() |> ignore member __.Message(msg: string) = MonoDevelop.Ide.IdeApp.Workbench.StatusBar.ShowMessage(msg) - //let _, frozen = statusBar.IsFrozen() - //// unfreeze the status bar - //if frozen <> 0 then statusBar.FreezeOutput 0 |> ignore - //statusBar.SetText msg |> ignore - //// freeze the status bar - //statusBar.FreezeOutput 1 |> ignore member this.TempMessage(msg: string) = this.Message(msg) - //this.Message msg - //async { - // do! Async.Sleep 4000 - // match statusBar.GetText() with - // | 0, currentText when currentText <> msg -> () - // | _ -> clear() - //}|> Async.Start member __.Clear() = clear() /// Animated magnifying glass that displays on the status bar while a symbol search is in progress. member __.Animate() : IDisposable = - //statusBar.Animation (1, &searchIcon) |> ignore { new IDisposable with - member __.Dispose() = () } //statusBar.Animation(0, &searchIcon) |> ignore } + member __.Dispose() = () } type internal FSharpGoToDefinitionNavigableItem(document, sourceSpan) = inherit FSharpNavigableItem(Glyph.BasicFile, ImmutableArray.Empty, document, sourceSpan) diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs index 9be89261984..11891f95b47 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs @@ -3,72 +3,12 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System.Threading -open System.Threading.Tasks open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.Editor -open Microsoft.CodeAnalysis.Host.Mef open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor -open System open System.ComponentModel.Composition; -open Microsoft.CodeAnalysis.Editor.Shared.Extensions; -open Microsoft.CodeAnalysis.Notification; -open Microsoft.CodeAnalysis.Shared.Extensions; -open Microsoft.CodeAnalysis.Text; -open Microsoft.VisualStudio.Commanding; -open Microsoft.VisualStudio.Text; -open Microsoft.VisualStudio.Text.Editor.Commanding.Commands; -[)>] -[] -[] -type internal FSharpGotoDefinitionCommandHandler - [] - ( - checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager - ) = - - let gtd = GoToDefinition(checkerProvider.Checker, projectInfoManager) - let statusBar = StatusBar((*ServiceProvider.GlobalProvider.GetService()*)) - interface ICommandHandler with - member __.DisplayName = "FSharp Go To Definition" - member __.GetCommandState(_args) = - CommandState.Available - - member __.ExecuteCommand(args, context) = - statusBar.Message(SR.LocatingSymbol()) - let subjectBuffer = args.SubjectBuffer - let document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges() - use __ = statusBar.Animate() - - let position = args.TextView.Caret.Position.Point.GetPoint(subjectBuffer, PositionAffinity.Predecessor).Value.Position - let gtdTask = gtd.FindDefinitionTask(document, position, context.OperationContext.UserCancellationToken) - - // Wrap this in a try/with as if the user clicks "Cancel" on the thread dialog, we'll be cancelled. - // Task.Wait throws an exception if the task is cancelled, so be sure to catch it. - try - // This call to Wait() is fine because we want to be able to provide the error message in the status bar. - gtdTask.Wait() - if gtdTask.Status = TaskStatus.RanToCompletion && gtdTask.Result.IsSome then - let item, _ = gtdTask.Result.Value - gtd.NavigateToItem(item, statusBar) - - // 'true' means do it, like Sheev Palpatine would want us to. - true - else - statusBar.TempMessage (SR.CannotDetermineSymbol()) - false - with exc -> - statusBar.TempMessage(String.Format(SR.NavigateToFailed(), Exception.flattenMessage exc)) - - // Don't show the dialog box as it's most likely that the user cancelled. - // Don't make them click twice. - true - //use __ = statusBar.Animate() - - //args.SubjectBuffer. [)>] [)>] type internal FSharpGoToDefinitionService @@ -79,7 +19,7 @@ type internal FSharpGoToDefinitionService ) = let gtd = GoToDefinition(checkerProvider.Checker, projectInfoManager) - let statusBar = StatusBar((*ServiceProvider.GlobalProvider.GetService()*)) + let statusBar = StatusBar() interface IFSharpGoToDefinitionService with /// Invoked with Peek Definition. @@ -99,26 +39,9 @@ type internal FSharpGoToDefinitionService match position with | Some (item, _) -> - - // Wrap this in a try/with as if the user clicks "Cancel" on the thread dialog, we'll be cancelled. - // Task.Wait throws an exception if the task is cancelled, so be sure to catch it. - //try - // This call to Wait() is fine because we want to be able to provide the error message in the status bar. - //gtdTask.Wait() - //if gtdTask.Status = TaskStatus.RanToCompletion && gtdTask.Result.IsSome then - gtd.NavigateToItem(item, statusBar) - - // 'true' means do it, like Sheev Palpatine would want us to. - //true + gtd.NavigateToItem(item, statusBar) | None -> - statusBar.TempMessage (SR.CannotDetermineSymbol()) - //false - //with exc -> - // statusBar.TempMessage(String.Format(SR.NavigateToFailed(), Exception.flattenMessage exc)) - - // // Don't show the dialog box as it's most likely that the user cancelled. - // // Don't make them click twice. - // true + statusBar.TempMessage (SR.CannotDetermineSymbol()) } Async.StartImmediate(computation, cancellationToken) true \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs index 647f4498d30..9889796f89d 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs @@ -2,43 +2,19 @@ namespace Microsoft.VisualStudio.FSharp.Editor -open System open System.Threading open System.Threading.Tasks open System.ComponentModel.Composition open Microsoft.CodeAnalysis.Text -open Microsoft.CodeAnalysis.Navigation open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Navigation open Microsoft.VisualStudio.Language.Intellisense open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor -//open Microsoft.VisualStudio.Shell.Interop -//open Microsoft.VisualStudio.Utilities -//open Microsoft.VisualStudio.Shell -open System.Composition -open System.Threading -open System.Threading.Tasks -open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.Editor -open Microsoft.CodeAnalysis.Host.Mef open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor -//open Microsoft.VisualStudio.Shell -////open Microsoft.VisualStudio.Shell.Interop -open System -open System; -open System.ComponentModel.Composition; -open Microsoft.CodeAnalysis.Editor.Shared.Extensions; -open Microsoft.CodeAnalysis.Notification; -open Microsoft.CodeAnalysis.Shared.Extensions; -open Microsoft.CodeAnalysis.Text; -open Microsoft.VisualStudio.Commanding; -open Microsoft.VisualStudio.Text; -open Microsoft.VisualStudio.Text.Editor.Commanding.Commands; - [] type internal FSharpNavigableSymbol(item: FSharpNavigableItem, span: SnapshotSpan, gtd: GoToDefinition, statusBar: StatusBar) = interface INavigableSymbol with @@ -53,7 +29,7 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider let mutable disposed = false let gtd = GoToDefinition(checkerProvider.Checker, projectInfoManager) - let statusBar = StatusBar((*serviceProvider.GetService()*)) + let statusBar = StatusBar() interface INavigableSymbolSource with member __.GetNavigableSymbolAsync(triggerSpan: SnapshotSpan, cancellationToken: CancellationToken) = @@ -66,9 +42,6 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider let document = snapshot.GetOpenDocumentInCurrentContextWithChanges() let! sourceText = document.GetTextAsync() |> liftTaskAsync - //statusBar.Message(SR.LocatingSymbol()) - //use _ = statusBar.Animate() - let gtdTask = gtd.FindDefinitionTask(document, position, cancellationToken) // Wrap this in a try/with as if the user clicks "Cancel" on the thread dialog, we'll be cancelled. @@ -76,7 +49,6 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider try // This call to Wait() is fine because we want to be able to provide the error message in the status bar. gtdTask.Wait() - //statusBar.Clear() if gtdTask.Status = TaskStatus.RanToCompletion && gtdTask.Result.IsSome then let navigableItem, range = gtdTask.Result.Value @@ -87,14 +59,8 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider return FSharpNavigableSymbol(navigableItem, symbolSpan, gtd, statusBar) :> INavigableSymbol else - //statusBar.TempMessage(SR.CannotDetermineSymbol()) - - // The NavigableSymbols API accepts 'null' when there's nothing to navigate to. return null with exc -> - //statusBar.TempMessage(String.Format(SR.NavigateToFailed(), Exception.flattenMessage exc)) - - // The NavigableSymbols API accepts 'null' when there's nothing to navigate to. return null } |> Async.map Option.toObj @@ -110,11 +76,10 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider type internal FSharpNavigableSymbolService [] ( - //[)>] serviceProvider: IServiceProvider, checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager ) = interface INavigableSymbolSourceProvider with member __.TryCreateNavigableSymbolSource(_: ITextView, _: ITextBuffer) = - new FSharpNavigableSymbolSource(checkerProvider, projectInfoManager(*, serviceProvider*)) :> INavigableSymbolSource \ No newline at end of file + new FSharpNavigableSymbolSource(checkerProvider, projectInfoManager) :> INavigableSymbolSource \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs index dd6819811be..3454a5bcc32 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs @@ -7,18 +7,12 @@ open System.IO open System.Composition open System.Collections.Generic open System.Collections.Immutable -open System.Threading open System.Threading.Tasks -open System.Runtime.CompilerServices open System.Runtime.Caching open System.Globalization open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.Host.Mef open Microsoft.CodeAnalysis.Text -open Microsoft.CodeAnalysis.NavigateTo -open Microsoft.CodeAnalysis.Navigation -open Microsoft.CodeAnalysis.PatternMatching open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Navigation open Microsoft.CodeAnalysis.ExternalAccess.FSharp.NavigateTo diff --git a/vsintegration/src/FSharp.Editor/Options/SettingsPersistence.fs b/vsintegration/src/FSharp.Editor/Options/SettingsPersistence.fs index 38e5e3724a9..f5b1598a0c9 100644 --- a/vsintegration/src/FSharp.Editor/Options/SettingsPersistence.fs +++ b/vsintegration/src/FSharp.Editor/Options/SettingsPersistence.fs @@ -15,7 +15,7 @@ type IPersistSettings = [] type SVsSettingsPersistenceManager = class end -type SettingsStore((*serviceProvider: IServiceProvider*)) = +type SettingsStore() = //let settingsManager = serviceProvider.GetService(typeof) :?> ISettingsManager diff --git a/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs b/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs index ac8319a4f98..45cb96f5c9c 100644 --- a/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs +++ b/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs @@ -12,5 +12,4 @@ open Mono.Addins [] [] -//[] () \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index 1dfa4210ca9..6685f85bd4f 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -158,7 +158,6 @@ module internal FSharpQuickInfo = type internal FSharpAsyncQuickInfoSource ( statusBar: StatusBar, - //xmlMemberIndexService: IVsXMLMemberIndexService, checkerProvider:FSharpCheckerProvider, projectInfoManager:FSharpProjectOptionsManager, textBuffer:ITextBuffer, @@ -233,7 +232,6 @@ type internal FSharpAsyncQuickInfoSource | Some _sigQuickInfo, Some targetQuickInfo -> let mainDescription, targetDocumentation, sigDocumentation, typeParameterMap, exceptions, usage = ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray() - //XmlDocumentation.BuildDataTipText(documentationBuilder, ignore, sigDocumentation.Add, ignore, ignore, ignore, sigQuickInfo.StructuredText) XmlDocumentation.BuildDataTipText(documentationBuilder, mainDescription.Add, targetDocumentation.Add, typeParameterMap.Add, exceptions.Add, usage.Add, targetQuickInfo.StructuredText) // get whitespace nomalized documentation text let getText (tts: seq) = @@ -270,7 +268,6 @@ type internal FSharpAsyncQuickInfoSource type internal FSharpAsyncQuickInfoSourceProvider [] ( - //[)>] serviceProvider: IServiceProvider, checkerProvider:FSharpCheckerProvider, projectInfoManager:FSharpProjectOptionsManager, settings: EditorOptions @@ -280,6 +277,5 @@ type internal FSharpAsyncQuickInfoSourceProvider override __.TryCreateQuickInfoSource(textBuffer) = // GetService calls must be made on the UI thread // It is safe to do it here (see #4713) - let statusBar = StatusBar((*serviceProvider.GetService()*)) - //let xmlMemberIndexService = serviceProvider.XMLMemberIndexService - new FSharpAsyncQuickInfoSource(statusBar, (* xmlMemberIndexService,*) checkerProvider, projectInfoManager, textBuffer, settings) :> _ + let statusBar = StatusBar() + new FSharpAsyncQuickInfoSource(statusBar, checkerProvider, projectInfoManager, textBuffer, settings) :> _ diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/Views.fs b/vsintegration/src/FSharp.Editor/QuickInfo/Views.fs index 371a240b276..96866890687 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/Views.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/Views.fs @@ -75,7 +75,6 @@ module internal QuickInfoViewProvider = match item with | :? Layout.NavigableTaggedText as nav when navigation.IsTargetValid nav.Range -> flushRuns() - //let navigableTextRun = NavigableTextRun(classificationTag, item.Text, fun () -> navigation.NavigateTo nav.Range) let navigableTextRun = ClassifiedTextElement.CreateHyperlink(item.Text, "Navigate to " + item.Text, fun() -> navigation.NavigateTo nav.Range) currentContainerItems.Add(navigableTextRun :> obj) | _ when item.Tag = LineBreak -> diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs b/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs deleted file mode 100644 index e56aa889361..00000000000 --- a/vsintegration/src/FSharp.Editor/QuickInfo/WpfNagivableTextRunViewElementFactory.fs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. - -namespace Microsoft.VisualStudio.FSharp.Editor - -open System -open System.ComponentModel.Composition -open System.Windows -//open System.Windows.Controls - -open Microsoft.VisualStudio.Text.Adornments -open Microsoft.VisualStudio.Text.Editor -open Microsoft.VisualStudio.Utilities -type UIElement = Xwt.Widget - -//[)>] -[] -[, typeof)>] -[] -type WpfNavigableTextRunViewElementFactory - [] - ( - viewElementFactoryService:IViewElementFactoryService, - settings: EditorOptions - ) = - //let styles = Microsoft.VisualStudio.FSharp.UIResources.NavStyles() - interface IViewElementFactory with - override __.CreateViewElement<'TView when 'TView: not struct>(textView:ITextView, model:obj) : 'TView = - if not (model :? NavigableTextRun) || typeof<'TView> <> typeof then - failwith <| sprintf "Invalid type conversion. Supported conversion is `%s` to `%s`." typeof.Name typeof.Name - - // use the default converters to get a UIElement - let navigableTextRun = model :?> NavigableTextRun - let classifiedTextRun = ClassifiedTextRun(navigableTextRun.ClassificationTypeName, navigableTextRun.Text) - let classifiedTextElement = ClassifiedTextElement([classifiedTextRun]) - let convertedElement = viewElementFactoryService.CreateViewElement(textView, classifiedTextElement) - let link = new Xwt.LinkLabel(navigableTextRun.Text) - //link.Text <- navigableTextRun.Text - //link :> 'TView - //// apply HTML-like styles - //match convertedElement with - //| :? TextBlock as tb -> - //let underlineStyle = - // let key = - // if settings.QuickInfo.DisplayLinks then - // match settings.QuickInfo.UnderlineStyle with - // | QuickInfoUnderlineStyle.Solid -> "solid_underline" - // | QuickInfoUnderlineStyle.Dash -> "dash_underline" - // | QuickInfoUnderlineStyle.Dot -> "dot_underline" - // else - // "no_underline" - // styles.Resources.[key] :?> Style - - //// we need to enclose the generated Inline, which is actually a Run element, - //// because fancy styling does not seem to work properly with Runs - //let inl = tb.Inlines.FirstInline - //let color = inl.Foreground - //// clear the color here to make it inherit - //inl.ClearValue(Documents.TextElement.ForegroundProperty) |> ignore - //// this constructor inserts into TextBlock - //Documents.Underline(tb.Inlines.FirstInline, tb.ContentStart, Foreground = color) |> ignore - //tb.Resources.[typeof] <- underlineStyle - //| _ -> () - - // add navigation - link.ButtonReleased.Add(fun _ -> navigableTextRun.NavigateAction()) - link :> obj :?> 'TView diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs index b146c416a16..052bd956adf 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractivePad.fs @@ -34,7 +34,6 @@ open FSharp.Editor open Gtk open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor -open Microsoft.VisualStudio.Core.Imaging open Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor @@ -250,7 +249,6 @@ type FSharpInteractivePad() as this = let docFileName = IdeApp.Workbench.ActiveDocument.FileName.ToString() if docFileName <> null then let directoryName = Path.GetDirectoryName docFileName - //ctx.WorkingFolder <- Some directoryName Some docFileName else None else None @@ -258,35 +256,19 @@ type FSharpInteractivePad() as this = let input = new ResizeArray<_>() let setupSession() = - //try - let pathToExe = - Path.Combine(Reflection.Assembly.GetExecutingAssembly().Location |> Path.GetDirectoryName, "MonoDevelop.FSharpInteractive.Service.exe") - |> ProcessArgumentBuilder.Quote - let ses = InteractiveSession(pathToExe) - let controller = new InteractivePadController(ses) - this.Controller <- Some controller - this.Host <- new GtkNSViewHost(controller.View) - this.Host.ShowAll() - input.Clear() - let textReceived = ses.TextReceived.Subscribe(fun t -> - Runtime.RunInMainThread(fun () -> controller.FsiOutput t) |> ignore) - //let imageReceived = ses.ImageReceived.Subscribe(fun image -> Runtime.RunInMainThread(fun () -> renderImage image) |> Async.AwaitTask |> Async.RunSynchronously) - let promptReady = ses.PromptReady.Subscribe(fun () -> Runtime.RunInMainThread(fun () -> controller.SetPrompt() ) |> ignore) - - //ses.Exited.Add(fun _ -> - // if killIntent = NoIntent then - // Runtime.RunInMainThread(fun () -> - // LoggingService.LogDebug ("Interactive: process stopped") - // (*this.FsiOutput "\nSession termination detected. Press Enter to restart." *))|> ignore - // elif killIntent = Restart then - // Runtime.RunInMainThread (fun () -> controller.Clear()) |> ignore - // killIntent <- NoIntent) - - //Some(ses) - ses - //with - //| e -> - // None + let pathToExe = + Path.Combine(Reflection.Assembly.GetExecutingAssembly().Location |> Path.GetDirectoryName, "MonoDevelop.FSharpInteractive.Service.exe") + |> ProcessArgumentBuilder.Quote + let ses = InteractiveSession(pathToExe) + let controller = new InteractivePadController(ses) + this.Controller <- Some controller + this.Host <- new GtkNSViewHost(controller.View) + this.Host.ShowAll() + input.Clear() + ses.TextReceived.Add(fun t -> + Runtime.RunInMainThread(fun () -> controller.FsiOutput t) |> ignore) + ses.PromptReady.Add(fun () -> Runtime.RunInMainThread(fun () -> controller.SetPrompt() ) |> ignore) + ses let mutable session = None @@ -374,7 +356,7 @@ type FSharpInteractivePad() as this = LoggingService.LogDebug ("FSI: #LoadReferences") async { let! orderedReferences = project.GetOrderedReferences (CompilerArguments.getConfig()) - orderedReferences |> List.iter (fun a -> (*x.SendCommand (sprintf @"#r ""%s""" a.Path)) *) ()) + orderedReferences |> List.iter (fun a -> x.SendCommand (sprintf @"#r ""%s""" a.Path)) } |> Async.StartImmediate member val Host:GtkNSViewHost = null with get, set @@ -398,7 +380,6 @@ type FSharpInteractivePad() as this = let ses = setupSession() session <- ses |> Some - //container.PadShown.Add(fun _args -> session <- setupSession()) container.PadContentShown.Add(fun _args -> if not ses.HasStarted then ses.StartReceiving() |> ignore) member x.RestartFsi() = resetFsi Restart diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs index 137341ae62b..1c643186b58 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs @@ -165,23 +165,6 @@ type InteractiveSession(pathToExe) = fsiProcess.Kill() fsiProcess <- startProcess() - //member x.Kill() = - // //if not fsiProcess.HasExited then - // // x.SendInput "#q;;" None - // // for i in 0 .. 10 do - // // if not fsiProcess.HasExited then - // // LoggingService.logDebug "Interactive: waiting for process exit after #q... %d" (i*200) - // // fsiProcess.WaitForExit(200) |> ignore - - // if not fsiProcess.HasExited then - // fsiProcess.Kill() - // for i in 0 .. 10 do - // if not fsiProcess.HasExited then - // LoggingService.logDebug "Interactive: waiting for process exit after kill... %d" (i*200) - // fsiProcess.WaitForExit(200) |> ignore - - //member x.KillNow() = fsiProcess.Kill() - member x.SendInput input documentName = documentName |> Option.iter(fun fileName -> diff --git a/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs index c1459db5875..cb45fa4023e 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/SignatureHelp.fs @@ -14,15 +14,12 @@ open Microsoft.VisualStudio.Text open FSharp.Compiler.Layout open FSharp.Compiler.Range open FSharp.Compiler.SourceCodeServices -open MonoDevelop.FSharp [] [)>] type internal FSharpInteractiveSignatureHelpProvider [] ( - //checkerProvider: FSharpCheckerProvider, - //projectInfoManager: FSharpProjectOptionsManager ) = static let userOpName = "SignatureHelpProvider" From 1ec2ab13c87d500826b4d74f487852e9f11e8b04 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 30 Apr 2020 12:47:18 +0100 Subject: [PATCH 091/101] Remove unneeded overrides in FSharpProject --- .../src/FSharp.Editor/Common/FSharpProject.fs | 54 ------------------- 1 file changed, 54 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs b/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs index 7c4d4ffcc76..5215c5ac1f1 100644 --- a/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs +++ b/vsintegration/src/FSharp.Editor/Common/FSharpProject.fs @@ -272,45 +272,9 @@ type FSharpProject() as self = override x.OnGetSupportedClrVersions() = [| ClrVersion.Net_2_0; ClrVersion.Net_4_0; ClrVersion.Net_4_5; ClrVersion.Clr_2_1 |] - override x.OnFileAddedToProject(e) = - base.OnFileAddedToProject(e) - //if not self.Loading then MDLanguageService.invalidateFiles e - - override x.OnFileRemovedFromProject(e) = - base.OnFileRemovedFromProject(e) - //if not self.Loading then MDLanguageService.invalidateFiles e - - override x.OnFileRenamedInProject(e) = - base.OnFileRenamedInProject(e) - //if not self.Loading then MDLanguageService.invalidateFiles e - - override x.OnFilePropertyChangedInProject(e) = - base.OnFilePropertyChangedInProject(e) - //if not self.Loading then MDLanguageService.invalidateFiles e - - override x.OnReferenceAddedToProject(e) = - base.OnReferenceAddedToProject(e) - //if not self.Loading then MDLanguageService.invalidateProjectFile self.FileName - - override x.OnReferenceRemovedFromProject(e) = - base.OnReferenceRemovedFromProject(e) - //if not self.Loading then MDLanguageService.invalidateProjectFile self.FileName - - //override x.OnFileRenamedInProject(e)= - // base.OnFileRenamedInProject(e) - // if not self.Loading then invalidateProjectFile() - - override x.OnNameChanged(e)= - base.OnNameChanged(e) - //if not self.Loading then MDLanguageService.invalidateProjectFile self.FileName - override x.OnGetDefaultResourceId(projectFile) = projectFile.FilePath.FileName - override x.OnModified(e) = - base.OnModified(e) - //if not self.Loading && not self.IsReevaluating then MDLanguageService.invalidateProjectFile self.FileName - member x.GetOrderedReferences(config:ConfigurationSelector) = async { let orderAssemblyReferences = MonoDevelop.FSharp.OrderAssemblyReferences() @@ -328,21 +292,3 @@ type FSharpProject() as self = return orderAssemblyReferences.Order references } - member x.ReevaluateProject(e) = - let task = base.OnReevaluateProject (e) - - async { - do! task |> Async.AwaitTask - //MDLanguageService.invalidateProjectFile self.FileName - } - - //override x.OnReevaluateProject(monitor) = - //x.ReevaluateProject monitor |> Async.AwaitTask monitor.CancellationToken :> Task - - override x.OnDispose () = - //languageService.HideStatusIcon (string self.FileName.FullPath) - // FIXME: is it correct to do it every time a project is disposed? - //Should only be done on solution close - //langServ.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() - base.OnDispose () - From 98c80db6e93a40428df181ca5ca7270ab1bd8185 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 30 Apr 2020 14:45:38 +0100 Subject: [PATCH 092/101] Move PortableFSharpProjectFlavor to FSharp.Editor project --- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 1 + vsintegration/src/FSharp.Editor/FSharp.addin.xml | 5 ++--- .../FSharp.Editor/VSMac/PortableFSharpProjectFlavor.fs | 9 +++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/VSMac/PortableFSharpProjectFlavor.fs diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 352daed92f8..c3798ffecdc 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -258,6 +258,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index 5d788827b5b..242c7511ef6 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -18,7 +18,7 @@ - + @@ -53,8 +53,7 @@ - - + diff --git a/vsintegration/src/FSharp.Editor/VSMac/PortableFSharpProjectFlavor.fs b/vsintegration/src/FSharp.Editor/VSMac/PortableFSharpProjectFlavor.fs new file mode 100644 index 00000000000..d7d593a67d2 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/PortableFSharpProjectFlavor.fs @@ -0,0 +1,9 @@ +namespace FSharp.Editor + +open MonoDevelop.Projects + +type PortableFSharpProjectFlavor() = + inherit PortableDotNetProjectFlavor() + + override x.OnGetDefaultImports imports = + imports.Add @"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.Portable.FSharp.Targets" From 559e46286fcb8daea6414af9c9561001959b94fe Mon Sep 17 00:00:00 2001 From: nosami Date: Mon, 4 May 2020 13:19:50 +0100 Subject: [PATCH 093/101] rebase --- vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index c3798ffecdc..cf7c43549b0 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -192,7 +192,7 @@ - {BAF30090-4E79-4D11-9E8D-30104E933B04} + {4EDEC7A0-782C-41F5-9640-AF4DCD487016} Microsoft.CodeAnalysis.ExternalAccess.FSharp From e576c00cb7e4323086e2df79c33c80c0d771ae29 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 6 May 2020 12:56:50 +0100 Subject: [PATCH 094/101] Allow tests to kill fsi --- .../FSharp.Editor/VSMac/CompletionService.fs | 24 +++++++------------ .../FSharp.Editor/VSMac/InteractiveSession.fs | 5 ++-- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs index ab017591823..14c3d100062 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/CompletionService.fs @@ -3,30 +3,24 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System -open System.ComponentModel.Composition +open System.Collections.Generic; open System.Collections.Immutable +open System.ComponentModel.Composition +open System.Threading.Tasks + +open FSharp.Editor open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.Classification open Microsoft.CodeAnalysis.Completion -open Microsoft.CodeAnalysis.Host.Mef open Microsoft.CodeAnalysis.ExternalAccess.FSharp -open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +open Microsoft.CodeAnalysis.Text; open Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion +open Microsoft.VisualStudio.Text.Adornments; open Microsoft.VisualStudio.Text.Editor -open System.Threading.Tasks - -open System.Collections.Generic; -open Microsoft.CodeAnalysis.Classification -open Microsoft.CodeAnalysis.Text; open Microsoft.VisualStudio.Text; -open Microsoft.VisualStudio.Text.Adornments; -open MonoDevelop.FSharp -open FSharp.Compiler.SourceCodeServices -open System -open Microsoft.VisualStudio.Core.Imaging -open Microsoft.VisualStudio.Imaging -open FSharp.Compiler.Range type internal FSharpInteractiveCompletionService ( diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs index 1c643186b58..22e770eddb8 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs @@ -1,10 +1,11 @@ -namespace MonoDevelop.FSharp +namespace FSharp.Editor open System open System.IO open System.Diagnostics open System.Runtime.Serialization.Formatters.Binary open MonoDevelop.Core +open MonoDevelop.FSharp open Newtonsoft.Json open Microsoft.VisualStudio.FSharp.Editor.Extensions open Newtonsoft.Json.Converters @@ -160,7 +161,7 @@ type InteractiveSession(pathToExe) = member x.HasStarted = hasStarted member x.HasExited() = fsiProcess.HasExited - + member x.Kill() = fsiProcess.Kill() member x.Restart() = fsiProcess.Kill() fsiProcess <- startProcess() From 72c1734f7e2b3189e919203d63997f79a2010835 Mon Sep 17 00:00:00 2001 From: nosami Date: Wed, 13 May 2020 11:51:05 +0100 Subject: [PATCH 095/101] Move code from fsharpbinding to FSharp.Editor --- .../src/FSharp.Editor/Common/Pervasive.fs | 27 +- .../src/FSharp.Editor/FSharp.Editor.fsproj | 3 + .../src/FSharp.Editor/FSharp.addin.xml | 4 + .../VSMac/FSharpProjectFileNodeExtension.fs | 219 +++++++++++++ .../FSharp.Editor/VSMac/FSharpSymbolHelper.fs | 203 ++++++++++++ .../src/FSharp.Editor/VSMac/GlobalSearch.fs | 297 ++++++++++++++++++ .../FSharp.Editor/VSMac/InteractiveSession.fs | 2 + 7 files changed, 748 insertions(+), 7 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/VSMac/FSharpProjectFileNodeExtension.fs create mode 100644 vsintegration/src/FSharp.Editor/VSMac/FSharpSymbolHelper.fs create mode 100644 vsintegration/src/FSharp.Editor/VSMac/GlobalSearch.fs diff --git a/vsintegration/src/FSharp.Editor/Common/Pervasive.fs b/vsintegration/src/FSharp.Editor/Common/Pervasive.fs index 9dd525d609c..2732b083866 100644 --- a/vsintegration/src/FSharp.Editor/Common/Pervasive.fs +++ b/vsintegration/src/FSharp.Editor/Common/Pervasive.fs @@ -4,14 +4,15 @@ module Microsoft.VisualStudio.FSharp.Editor.Pervasive open System open System.IO open System.Diagnostics +open System.Threading.Tasks /// Checks if the filePath ends with ".fsi" -let isSignatureFile (filePath:string) = +let isSignatureFile (filePath:string) = String.Equals (Path.GetExtension filePath, ".fsi", StringComparison.OrdinalIgnoreCase) /// Checks if the file paht ends with '.fsx' or '.fsscript' -let isScriptFile (filePath:string) = - let ext = Path.GetExtension filePath +let isScriptFile (filePath:string) = + let ext = Path.GetExtension filePath String.Equals (ext, ".fsx", StringComparison.OrdinalIgnoreCase) || String.Equals (ext, ".fsscript", StringComparison.OrdinalIgnoreCase) type internal ISetThemeColors = abstract member SetColors: unit -> unit @@ -168,7 +169,7 @@ let asyncMaybe = AsyncMaybeBuilder() let inline liftAsync (computation : Async<'T>) : Async<'T option> = async { let! a = computation - return Some a + return Some a } let liftTaskAsync task = task |> Async.AwaitTask |> liftAsync @@ -180,7 +181,7 @@ module Async = return f a } - /// Creates an asynchronous workflow that runs the asynchronous workflow given as an argument at most once. + /// Creates an asynchronous workflow that runs the asynchronous workflow given as an argument at most once. /// When the returned workflow is started for the second time, it reuses the result of the previous execution. let cache (input : Async<'T>) = let agent = MailboxProcessor>.Start <| fun agent -> @@ -190,6 +191,18 @@ module Async = replyCh.Reply res while true do let! replyCh = agent.Receive () - replyCh.Reply res + replyCh.Reply res } - async { return! agent.PostAndAsyncReply id } \ No newline at end of file + async { return! agent.PostAndAsyncReply id } + + let inline awaitPlainTask (task: Task) = + task.ContinueWith (fun task -> if task.IsFaulted then raise task.Exception) + |> Async.AwaitTask + +[] +module AsyncTaskBind = + type Microsoft.FSharp.Control.AsyncBuilder with + member x.Bind(computation:Task<'T>, binder:'T -> Async<'R>) = x.Bind(Async.AwaitTask computation, binder) + member x.ReturnFrom(computation:Task<'T>) = x.ReturnFrom(Async.AwaitTask computation) + member x.Bind(computation:Task, binder:unit -> Async) = x.Bind(Async.awaitPlainTask computation, binder) + member x.ReturnFrom(computation:Task) = x.ReturnFrom(Async.awaitPlainTask computation) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index cf7c43549b0..35bc6d7680b 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -259,6 +259,9 @@ + + + diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index 242c7511ef6..c9d7f3635fd 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -140,4 +140,8 @@ --> + + + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/FSharpProjectFileNodeExtension.fs b/vsintegration/src/FSharp.Editor/VSMac/FSharpProjectFileNodeExtension.fs new file mode 100644 index 00000000000..aca41fc1923 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/FSharpProjectFileNodeExtension.fs @@ -0,0 +1,219 @@ +namespace MonoDevelop.FSharp + +open System.Linq +open System.Xml +open System.Xml.Linq + +module Linq2Xml = + let xn = XName.op_Implicit + let xs ns local = XName.Get(local, ns) + let firstOrDefault seq = Enumerable.FirstOrDefault(seq) + let firstOrNone seq = + let iter = Enumerable.FirstOrDefault(seq) + match iter with null -> None | _ -> Some(iter) + + let singleOrDefault seq = Enumerable.SingleOrDefault(seq) + let where (pred: XElement -> bool) elements = Enumerable.Where(elements, pred) + let attribute name (element:XElement) = element.Attribute <| xn name + let attributeValue name element = (attribute name element).Value + let descendants xs (element: XElement) = element.Descendants(xs) + let previousNodeOrNone (element: XElement) = + match element.PreviousNode with + | null -> None + | node -> Some(node) + +open System +open System.IO +open MonoDevelop.Core +open MonoDevelop.Ide.Gui.Components +open MonoDevelop.Projects +open MonoDevelop.Ide +open MonoDevelop.Ide.Gui.Pads.ProjectPad +open Linq2Xml + +/// The command handler type for nodes in F# projects in the solution explorer. +type FSharpProjectNodeCommandHandler() = + inherit NodeCommandHandler() + + /// Reload project causing the node tree up refresh with new ordering + let reloadProject (file: ProjectFile) = + use monitor = IdeApp.Workbench.ProgressMonitors.GetProjectLoadProgressMonitor(true) + monitor.BeginTask("Reloading Project", 1) |> ignore + file.Project.ParentFolder.ReloadItem(monitor, file.Project) |> ignore + monitor.Step (1) + monitor.EndTask() + + let fileIsInFSharpProject (file: ProjectFile) = + file.Project.SupportedLanguages |> Array.contains "F#" + + let rec moveNodeInXDoc (xdoc:XElement) (moveToNode: ProjectFile) (movingNode:ProjectFile) position isNested = + let descendantsNamed ns name ancestor = + ///partially apply the default namespace of msbuild to xs + let xd = xs ns + descendants (xd name) ancestor + + // If the "Compile" element contains a "Link" element then it is a linked file, + // so use that value for comparison when finding the node. + let nodeName ns (node:XElement) = + let link = node |> descendantsNamed ns "Link" |> firstOrNone + match link with + | Some l -> l.Value + | None -> node |> attributeValue "Include" + + let defaultNamespace = xdoc.GetDefaultNamespace().NamespaceName + let descendantsByNamespace = descendantsNamed defaultNamespace + //get movable nodes from the project file + let movableNodes = (descendantsByNamespace "Compile" xdoc). + Concat(descendantsByNamespace "EmbeddedResource" xdoc). + Concat(descendantsByNamespace "Content" xdoc). + Concat(descendantsByNamespace "None" xdoc) + + let findByIncludeFile name seq = + seq |> where (fun elem -> nodeName defaultNamespace elem = name ) + |> firstOrNone + + let getFullName (pf:ProjectFile) = pf.ProjectVirtualPath.ToString().Replace("/", "\\") + + let movingElement = movableNodes |> findByIncludeFile (getFullName movingNode) + let moveToElement = movableNodes |> findByIncludeFile (getFullName moveToNode) + + let addFunction (moveTo:XElement) (position:DropPosition) = + match position with + | DropPosition.Before -> moveTo.AddBeforeSelf : obj -> unit + | DropPosition.After -> moveTo.AddAfterSelf : obj -> unit + | _ -> ignore + + match (movingElement, moveToElement, position) with + | Some(moving), Some(moveTo), (DropPosition.Before | DropPosition.After) -> + moving.Remove() + // If the moving node contains a DependentUpon node as a child remove the DependentUpon nodes, + // only if the moving node was moved directly - not via moving the parent node + if not isNested then + moving |> descendantsByNamespace "DependentUpon" |> Seq.iter (fun node -> node.Remove()) + //get the add function using the position + let add = addFunction moveTo position + add(moving) + + // If any of the project files depend on the file + // being moved, then move those files below the file being moved + movingNode.Project.Files + |> Seq.filter(fun f -> f.DependsOnFile = movingNode) + |> Seq.iter(fun f -> moveNodeInXDoc xdoc movingNode f DropPosition.After true) + + | _ -> ()//If we cant find both nodes or the position isnt before or after we dont continue + + member x.MoveNodes (moveToNode: ProjectFile) (movingNode:ProjectFile) position = + let projectFile = movingNode.Project.FileName.ToString() + + let xdoc = XElement.Load(projectFile) + + moveNodeInXDoc xdoc moveToNode movingNode position false + + let settings = XmlWriterSettings(OmitXmlDeclaration = true, Indent = true) + use writer = XmlWriter.Create(projectFile, settings) + xdoc.Save(writer); + writer.Close() + + /// Implement drag and drop of nodes in F# projects in the solution explorer. + override x.OnNodeDrop(dataObject, dragOperation, position) = + match dataObject, dragOperation with + | :? ProjectFile as movingNode, DragOperation.Move -> + //Move as long as this is a drag op and the moving node is a project file + match x.CurrentNode.DataItem with + | :? ProjectFile as moveToNode -> + x.MoveNodes moveToNode movingNode position + reloadProject moveToNode + | _ -> ()//unsupported + | _ -> //otherwise use the base behaviour + base.OnNodeDrop(dataObject, dragOperation, position) + + /// Implement drag and drop of nodes in F# projects in the solution explorer. + override x.CanDragNode() = DragOperation.Move + + /// Implement drag and drop of nodes in F# projects in the solution explorer. + override x.CanDropNode(dataObject, _dragOperation) = + //currently we are going to only support dropping project files from the same parent project + match (dataObject, x.CurrentNode.DataItem) with + | (:? ProjectFile as drag), (:? ProjectFile as drop) when fileIsInFSharpProject drag && fileIsInFSharpProject drop -> + drag <> drop && + drag.Project = drop.Project && drop.ProjectVirtualPath.ParentDirectory = drag.ProjectVirtualPath.ParentDirectory + | _ -> false + + /// Implement drag and drop of nodes in F# projects in the solution explorer. + override x.CanDropNode(dataObject, dragOperation, _position) = + x.CanDropNode(dataObject, dragOperation) + //This would allow anything to be droppped as long as it was in the same project and path level + //We would need to add to moveNodes so it knows how to find ProvectFolders and other items that mught be present + // | drag, drop -> + // match getProjectAndPath drag, getProjectAndPath drop with + // | Some(project1, project1Path), Some(project2, project2Path) -> project1 = project2 && project1Path.ParentDirectory = project2Path.ParentDirectory + // | _ -> false + + +/// MD/XS extension for the F# project nodes in the solution explorer. +type FSharpProjectFileNodeExtension() = + inherit NodeBuilderExtension() + + let (|FSharpProject|_|) (project:Project) = + match project with + | :? DotNetProject as dnp when dnp.LanguageName = "F#" -> Some dnp + | _ -> None + + /// Check if an item in the project model is recognized by this extension. + let (|SupportedProjectFile|SupportedProjectFolder|NotSupported|) (item:obj) = + match item with + | :? ProjectFile as projfile when projfile.Project <> null -> + match projfile.Project with + | FSharpProject _ -> SupportedProjectFile(projfile) + | _ -> NotSupported + | :? ProjectFolder as projfolder when projfolder.Project <> null -> + match projfolder.Project with + | FSharpProject _ -> SupportedProjectFolder(projfolder) + | _ -> NotSupported + | _ -> NotSupported + + let findIndex thing = + match thing with + | SupportedProjectFile(file) -> file.Project.Files.IndexOf(file) + | SupportedProjectFolder(folder) -> + let childfile = + folder.Project.Files + |> Seq.tryFind (fun p -> + let filePath = + match p.IsLink with + | true -> + p.Link.ToAbsolute(folder.Project.FileName.ParentDirectory) + | false -> + p.FilePath + filePath.IsChildPathOf folder.Path) + + match childfile with + | Some file -> folder.Project.Files.IndexOf file + | None -> //fallback to finding a directory subtype + let folderIndex = + folder.Project.Files + |> Seq.filter (fun file -> file.Subtype = Subtype.Directory) + |> Seq.tryFindIndex(fun pf -> pf.FilePath = folder.Path) + match folderIndex with + | Some i -> i + | _ -> NodeBuilder.DefaultSort + | NotSupported -> NodeBuilder.DefaultSort + + + override x.CanBuildNode(dataType:Type) = + // Extend any file or folder belonging to a F# project + typedefof.IsAssignableFrom(dataType) || typedefof.IsAssignableFrom (dataType) + + member x.Compare (thisDataItem: 'a) (otherDataItem: 'a) = + match (thisDataItem, otherDataItem) with + | SupportedProjectFile thisNode, SupportedProjectFile other -> compare (findIndex thisNode) (findIndex other) + | SupportedProjectFolder thisNode, SupportedProjectFolder other -> compare (findIndex thisNode) (findIndex other) + | SupportedProjectFile thisNode, SupportedProjectFolder other -> compare (findIndex thisNode) (findIndex other) + | SupportedProjectFolder thisNode, SupportedProjectFile other -> compare (findIndex thisNode) (findIndex other) + | _ -> NodeBuilder.DefaultSort + + override x.CompareObjects(thisNode:ITreeNavigator, otherNode:ITreeNavigator) : int = + x.Compare thisNode.DataItem otherNode.DataItem + + override x.CommandHandlerType = typeof + diff --git a/vsintegration/src/FSharp.Editor/VSMac/FSharpSymbolHelper.fs b/vsintegration/src/FSharp.Editor/VSMac/FSharpSymbolHelper.fs new file mode 100644 index 00000000000..25f38f5f7fa --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/FSharpSymbolHelper.fs @@ -0,0 +1,203 @@ +namespace MonoDevelop.FSharp.Shared +open System +open System.Collections.Generic +open System.Text +open FSharp.Compiler +open FSharp.Compiler.SourceCodeServices + +module Symbols = + let getLocationFromSymbolUse (s: FSharpSymbolUse) = + [s.Symbol.DeclarationLocation; s.Symbol.SignatureLocation] + |> List.choose id + |> List.distinctBy (fun r -> r.FileName) + + let getLocationFromSymbol (s:FSharpSymbol) = + [s.DeclarationLocation; s.SignatureLocation] + |> List.choose id + |> List.distinctBy (fun r -> r.FileName) + +[] +module SymbolUse = + let (|ActivePatternCase|_|) (symbol : FSharpSymbolUse) = + match symbol.Symbol with + | :? FSharpActivePatternCase as ap-> ActivePatternCase(ap) |> Some + | _ -> None + + let (|Entity|_|) (symbol : FSharpSymbolUse) = + match symbol.Symbol with + | :? FSharpEntity as ent -> Some ent + | _ -> None + + let (|Field|_|) (symbol : FSharpSymbolUse) = + match symbol.Symbol with + | :? FSharpField as field-> Some field + | _ -> None + + let (|GenericParameter|_|) (symbol: FSharpSymbolUse) = + match symbol.Symbol with + | :? FSharpGenericParameter as gp -> Some gp + | _ -> None + + let (|MemberFunctionOrValue|_|) (symbol : FSharpSymbolUse) = + match symbol.Symbol with + | :? FSharpMemberOrFunctionOrValue as func -> Some func + | _ -> None + + let (|ActivePattern|_|) = function + | MemberFunctionOrValue m when m.IsActivePattern -> Some m | _ -> None + + let (|Parameter|_|) (symbol : FSharpSymbolUse) = + match symbol.Symbol with + | :? FSharpParameter as param -> Some param + | _ -> None + + let (|StaticParameter|_|) (symbol : FSharpSymbolUse) = + match symbol.Symbol with + | :? FSharpStaticParameter as sp -> Some sp + | _ -> None + + let (|UnionCase|_|) (symbol : FSharpSymbolUse) = + match symbol.Symbol with + | :? FSharpUnionCase as uc-> Some uc + | _ -> None + + let (|Constructor|_|) = function + | MemberFunctionOrValue func when func.IsConstructor || func.IsImplicitConstructor -> Some func + | _ -> None + + let (|TypeAbbreviation|_|) = function + | Entity symbol when symbol.IsFSharpAbbreviation -> Some symbol + | _ -> None + + let (|Class|_|) = function + | Entity symbol when symbol.IsClass -> Some symbol + | Entity s when s.IsFSharp && + s.IsOpaque && + not s.IsFSharpModule && + not s.IsNamespace && + not s.IsDelegate && + not s.IsFSharpUnion && + not s.IsFSharpRecord && + not s.IsInterface && + not s.IsValueType -> Some s + | _ -> None + + let (|Delegate|_|) = function + | Entity symbol when symbol.IsDelegate -> Some symbol + | _ -> None + + let (|Event|_|) = function + | MemberFunctionOrValue symbol when symbol.IsEvent -> Some symbol + | _ -> None + + let (|Property|_|) = function + | MemberFunctionOrValue symbol when symbol.IsProperty || symbol.IsPropertyGetterMethod || symbol.IsPropertySetterMethod -> Some symbol + | _ -> None + + let inline private notCtorOrProp (symbol:FSharpMemberOrFunctionOrValue) = + not symbol.IsConstructor && not symbol.IsPropertyGetterMethod && not symbol.IsPropertySetterMethod + + let (|Method|_|) (symbolUse:FSharpSymbolUse) = + match symbolUse with + | MemberFunctionOrValue symbol when symbol.IsModuleValueOrMember && + not symbolUse.IsFromPattern && + not symbol.IsOperatorOrActivePattern && + not symbol.IsPropertyGetterMethod && + not symbol.IsPropertySetterMethod -> Some symbol + | _ -> None + + let (|Function|_|) (symbolUse:FSharpSymbolUse) = + match symbolUse with + | MemberFunctionOrValue symbol when notCtorOrProp symbol && + symbol.IsModuleValueOrMember && + not symbol.IsOperatorOrActivePattern && + not symbolUse.IsFromPattern -> + match symbol.FullTypeSafe with + | Some fullType when fullType.IsFunctionType -> Some symbol + | _ -> None + | _ -> None + + let (|Operator|_|) (symbolUse:FSharpSymbolUse) = + match symbolUse with + | MemberFunctionOrValue symbol when notCtorOrProp symbol && + not symbolUse.IsFromPattern && + not symbol.IsActivePattern && + symbol.IsOperatorOrActivePattern -> + match symbol.FullTypeSafe with + | Some fullType when fullType.IsFunctionType -> Some symbol + | _ -> None + | _ -> None + + let (|Pattern|_|) (symbolUse:FSharpSymbolUse) = + match symbolUse with + | MemberFunctionOrValue symbol when notCtorOrProp symbol && + not symbol.IsOperatorOrActivePattern && + symbolUse.IsFromPattern -> + match symbol.FullTypeSafe with + | Some fullType when fullType.IsFunctionType ->Some symbol + | _ -> None + | _ -> None + + + let (|ClosureOrNestedFunction|_|) = function + | MemberFunctionOrValue symbol when notCtorOrProp symbol && + not symbol.IsOperatorOrActivePattern && + not symbol.IsModuleValueOrMember -> + match symbol.FullTypeSafe with + | Some fullType when fullType.IsFunctionType -> Some symbol + | _ -> None + | _ -> None + + + let (|Val|_|) = function + | MemberFunctionOrValue symbol when notCtorOrProp symbol && + not symbol.IsOperatorOrActivePattern -> + match symbol.FullTypeSafe with + | Some _fullType -> Some symbol + | _ -> None + | _ -> None + + let (|Enum|_|) = function + | Entity symbol when symbol.IsEnum -> Some symbol + | _ -> None + + let (|Interface|_|) = function + | Entity symbol when symbol.IsInterface -> Some symbol + | _ -> None + + let (|Module|_|) = function + | Entity symbol when symbol.IsFSharpModule -> Some symbol + | _ -> None + + let (|Namespace|_|) = function + | Entity symbol when symbol.IsNamespace -> Some symbol + | _ -> None + + let (|Record|_|) = function + | Entity symbol when symbol.IsFSharpRecord -> Some symbol + | _ -> None + + let (|Union|_|) = function + | Entity symbol when symbol.IsFSharpUnion -> Some symbol + | _ -> None + + let (|ValueType|_|) = function + | Entity symbol when symbol.IsValueType && not symbol.IsEnum -> Some symbol + | _ -> None + + let (|ComputationExpression|_|) (symbol:FSharpSymbolUse) = + if symbol.IsFromComputationExpression then Some symbol + else None + + let (|Attribute|_|) = function + | Entity ent -> + if ent.AllBaseTypes + |> Seq.exists (fun t -> + if t.HasTypeDefinition then + t.TypeDefinition.TryFullName + |> Option.exists ((=) "System.Attribute" ) + else false) + then Some ent + else None + | _ -> None + diff --git a/vsintegration/src/FSharp.Editor/VSMac/GlobalSearch.fs b/vsintegration/src/FSharp.Editor/VSMac/GlobalSearch.fs new file mode 100644 index 00000000000..1ac50bff977 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/GlobalSearch.fs @@ -0,0 +1,297 @@ +namespace MonoDevelop.FSharp +open System.Collections.Generic +open System.Threading.Tasks +open MonoDevelop.Core +open MonoDevelop.Core.Text +open MonoDevelop.Components.MainToolbar +open MonoDevelop.Ide +open MonoDevelop.Ide.Gui +open MonoDevelop.Projects +open FSharp.Compiler.SourceCodeServices +open MonoDevelop.FSharp.Shared +open MonoDevelop.Ide.Composition +open Microsoft.VisualStudio.FSharp.Editor +open MonoDevelop.Ide.TypeSystem + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.ExternalAccess.FSharp +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.FindUsages +open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.FindUsages +open FSharp.Compiler.Range +open FSharp.Compiler.SourceCodeServices +[] +module Accessibility = + let inline getImage name = ImageService.GetIcon( name, Gtk.IconSize.Menu) + + let inline getImageFromAccessibility pub inter priv typeWithAccessibility = + let accessibility = (^a : (member Accessibility : FSharpAccessibility) typeWithAccessibility) + if accessibility.IsPublic then getImage pub + elif accessibility.IsInternal then getImage inter + else getImage priv + +module DisplayName = + let correct(symbol:FSharpSymbolUse) = + match symbol with + | SymbolUse.Constructor c -> + match c.DeclaringEntity with + | Some ent -> ent.DisplayName + | _ -> LoggingService.LogError(sprintf "Constructor with no EnclosingEntity: %s" c.DisplayName) + c.DisplayName + | _ -> symbol.Symbol.DisplayName + + +type SymbolSearchResult(match', matchedString, rank, symbol:FSharpSymbolUse, span:FSharpDocumentSpan) = + inherit SearchResult(match', matchedString, rank) + + let simpleName = DisplayName.correct symbol + //let offsetAndLength = lazy Symbols.getOffsetAndLength simpleName symbol + + override x.SearchResultType = + match symbol with + | SymbolUse.Record _ | SymbolUse.Module _ | SymbolUse.ValueType _ | SymbolUse.Delegate _ | SymbolUse.Union _ | SymbolUse.Class _ + | SymbolUse.Namespace _ | SymbolUse.Interface _ | SymbolUse.Enum _ | SymbolUse.ActivePattern _ -> SearchResultType.Type + + | SymbolUse.ActivePatternCase _ | SymbolUse.Field _ | SymbolUse.UnionCase _ | SymbolUse.Property _ + | SymbolUse.Event _ | SymbolUse.Operator _ | SymbolUse.Constructor _ | SymbolUse.Function _ | SymbolUse.Val _-> SearchResultType.Member + | _ -> SearchResultType.Unknown + + override x.Description = + let cat = + match symbol with + | SymbolUse.Record _ -> "record" + | SymbolUse.Module _ -> "module" + | SymbolUse.ValueType _ -> "struct" + | SymbolUse.Delegate _ -> "delegate" + | SymbolUse.Union _ -> "union" + | SymbolUse.Class c -> if c.IsFSharp then "type" else "class" + | SymbolUse.Namespace _ -> "namespace" + | SymbolUse.Interface _ -> "interface" + | SymbolUse.Enum _ -> "enum" + | SymbolUse.ActivePattern _ -> "active pattern" + | SymbolUse.Field _ -> "field" + | SymbolUse.UnionCase _ -> "union case" + | SymbolUse.Property _ -> "property" + | SymbolUse.Event _ -> "event" + | SymbolUse.Operator _ -> "operator" + | SymbolUse.Constructor _ -> "constructor" + | SymbolUse.Method _ -> "method" + | SymbolUse.Function _ -> "function" + | SymbolUse.Val _ -> "val" + | _ -> "symbol" + sprintf "%s (file %s)" cat symbol.RangeAlternate.FileName + + override x.PlainText = simpleName + + override x.File = symbol.RangeAlternate.FileName + override x.Icon = + match symbol with + | SymbolUse.Record _ -> getImage "md-type" + | SymbolUse.Module _ -> getImage "md-module" + | SymbolUse.ValueType s -> s |> getImageFromAccessibility Stock.Struct.Name Stock.InternalStruct.Name Stock.PrivateStruct.Name + | SymbolUse.Delegate d -> d |> getImageFromAccessibility Stock.Delegate.Name Stock.InternalDelegate.Name Stock.PrivateDelegate.Name + | SymbolUse.Union _ -> getImage "md-type" + | SymbolUse.Class c -> if c.IsFSharp then getImage "md-type" else c |> getImageFromAccessibility Stock.Class.Name Stock.InternalClass.Name Stock.PrivateClass.Name + | SymbolUse.Namespace _ -> getImage Stock.NameSpace.Name + | SymbolUse.Interface i -> i |> getImageFromAccessibility Stock.Interface.Name Stock.InternalInterface.Name Stock.PrivateInterface.Name + | SymbolUse.Enum e -> e |> getImageFromAccessibility Stock.Enum.Name Stock.InternalEnum.Name Stock.PrivateEnum.Name + | SymbolUse.ActivePattern _ -> getImage "md-type" + | SymbolUse.Field f ->f |> getImageFromAccessibility Stock.Field.Name Stock.InternalField.Name Stock.PrivateField.Name + | SymbolUse.UnionCase _ -> getImage "md-type" + | SymbolUse.Property p -> p |> getImageFromAccessibility Stock.Property.Name Stock.InternalProperty.Name Stock.PrivateProperty.Name + | SymbolUse.Event e -> e |> getImageFromAccessibility Stock.Event.Name Stock.InternalEvent.Name Stock.PrivateEvent.Name + | SymbolUse.Operator _ -> getImage "md-fs-field" + | SymbolUse.Constructor c -> c |> getImageFromAccessibility Stock.Method.Name Stock.InternalMethod.Name Stock.PrivateMethod.Name + | SymbolUse.Function mfv -> + if mfv.IsExtensionMember then mfv |> getImageFromAccessibility "md-extensionmethod" "md-internal-extensionmethod" "md-private-extensionmethod" + elif mfv.IsMember then mfv |> getImageFromAccessibility Stock.Method.Name Stock.InternalMethod.Name Stock.PrivateMethod.Name + else getImage "md-fs-field" + | SymbolUse.Val _ -> getImage "md-fs-field" //NOTE: Maybe make this a normal field icon? + | _ -> getImage Stock.Event.Name + + //override x.GetTooltipInformation(token) = + // SymbolTooltips.getTooltipInformation symbol |> StartAsyncAsTask token + + override x.Offset = span.SourceSpan.Start// fst (offsetAndLength.Force()) + override x.Length = span.SourceSpan.Length// snd (offsetAndLength.Force()) + +module GlobalSearch = + let inline private is expr s = + match expr s with Some _ -> true | None -> false + + let private filter tag (s:FSharpSymbolUse seq) = + match tag with + | "type" | "t" | "c" -> s |> Seq.filter (is (|Class|_|)) + | "mod" -> s |> Seq.filter (is (|Module|_|)) + | "s" -> s |> Seq.filter (is (|ValueType|_|)) + | "i" -> s |> Seq.filter (is (|Interface|_|)) + | "e" -> s |> Seq.filter (is (|Enum|_|)) + | "d" -> s |> Seq.filter (is (|Delegate|_|)) + | "u" -> s |> Seq.filter (is (|Union|_|)) + | "r" -> s |> Seq.filter (is (|Record|_|)) + | "member" | "m" -> s |> Seq.filter (is (|Method|_|)) + | "p" -> s |> Seq.filter (is (|Property|_|)) + | "f" -> s |> Seq.filter (is (|Field|_|)) + | "ap" -> s |> Seq.filter (is (|ActivePattern|_|)) + | "op" -> s |> Seq.filter (is (|Operator|_|)) + | _ -> s + + let byTag tag (items: FSharpSymbolUse seq) = + let filtered = items |> filter tag + filtered + + let getAllFSharpProjects() = + seq { for p in IdeApp.Workspace.GetAllProjects() do + if p.SupportedLanguages |> Array.contains "F#" then + yield p } + + let byPattern (cache:Dictionary<_,_>) pattern symbols = + + let matchName (matcher:StringMatcher) (name:string) = + if name = null then (false, -1) + else + match cache.TryGetValue(name) with + | true, v -> v + | false, _ -> + let doesMatch, rank = matcher.CalcMatchRank (name) + let savedMatch = (doesMatch, rank) + cache.Add(name, savedMatch) + savedMatch + + let matcher = StringMatcher.GetMatcher (pattern, false) + + symbols + |> Seq.choose (fun s -> let doesMatch, rank = matchName matcher (DisplayName.correct s) + if doesMatch then Some(s, rank) + else None) + + // File can be included in more than one project, hence single `range` may results with multiple `Document`s. + let rangeToDocumentSpans (solution: Solution, range: range) = + async { + if range.Start = range.End then return [] + else + let! spans = + solution.GetDocumentIdsWithFilePath(range.FileName) + |> Seq.map (fun documentId -> + async { + let doc = solution.GetDocument(documentId) + let! cancellationToken = Async.CancellationToken + let! sourceText = doc.GetTextAsync(cancellationToken) |> Async.AwaitTask + match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range) with + | Some span -> + let span = Tokenizer.fixupSpan(sourceText, span) + return Some (FSharpDocumentSpan(doc, span)) + | None -> return None + }) + |> Async.Parallel + return spans |> Array.choose id |> Array.toList + } + + let internal getSymbolUsesInWorkspace (projectInfoManager: FSharpProjectOptionsManager) (pattern: SearchPopupSearchPattern) (callback: ISearchResultCallback) token = + let (workspace: MonoDevelopWorkspace) = downcast IdeApp.TypeSystemService.Workspace + + let cachingSearch = byPattern (Dictionary<_,_>()) + workspace.CurrentSolution.Projects + |> Seq.filter(fun project -> project.Language = "F#") + |> Seq.map (fun project -> + async { + match! projectInfoManager.TryGetOptionsByProject(project, token) with + | Some (_parsingOptions, projectOptions) -> + let! projectCheckResults = projectInfoManager.Checker.ParseAndCheckProject(projectOptions, userOpName = "F# Global Search") + let! allProjectSymbols = projectCheckResults.GetAllUsesOfAllSymbols() + //LoggingService.LogInfo(sprintf "F# Global Search: Filtering %i project symbols from %s, for definitions" (allProjectSymbols |> Seq.length) shortName ) + let definitions = allProjectSymbols |> Seq.filter (fun s -> s.IsFromDefinition) + + //LoggingService.LogInfo(sprintf "F# Global Search: Filtering %i matching tag %s for %s" (definitions |> Seq.length) pattern.Tag shortName ) + let tagFiltered = definitions |> byTag pattern.Tag + + //LoggingService.LogInfo(sprintf "F# Global Search: Caching search on %i typeFilteredSymbols for matching pattern %s on %s" (tagFiltered |> Seq.length) pattern.Pattern shortName ) + let matchedSymbols = tagFiltered |> cachingSearch pattern.Pattern + + //LoggingService.LogInfo(sprintf "F# Global Search: Matched %i symbols from %s" (matchedSymbols |> Seq.length) shortName ) + for symbol:FSharpSymbolUse, rank in matchedSymbols do + let! spans = rangeToDocumentSpans (workspace.CurrentSolution, symbol.RangeAlternate) + for span in spans do + let sr = SymbolSearchResult(pattern.Pattern, symbol.Symbol.DisplayName, rank, symbol, span) + callback.ReportResult sr + //let distinctUses = uses |> Array.distinctBy (fun symbolUse -> symbolUse.RangeAlternate) + //return distinctUses + | None -> ()//return [||] + }) + |> Async.Parallel + |> Async.Ignore + // FCS may return several `FSharpSymbolUse`s for same range, which have different `ItemOccurrence`s (Use, UseInAttribute, UseInType, etc.) + // We don't care about the occurrence type here, so we distinct by range. + //|> Async.map (Array.distinctBy (fun x -> x.RangeAlternate)) + + //let getAllProjectSymbols (project: Project) = + // asyncMaybe { + // try + // let filename = "test.fsx" + // let optionsManager = CompositionManager.Instance.GetExportedValue() + // let checker = optionsManager.Checker + // let! projectId = IdeApp.TypeSystemService.GetCodeAnalysisProjectAsync(project) |> liftTaskAsync + // let! parseResults , projOptions = optionsManager.TryGetOptionsByProject(projectId, Async.DefaultCancellationToken) + // //let sourceText = SourceText.ofString source + // //let! projOptions, _errors = checker.GetProjectOptions + // let! checkResults = checker.ParseAndCheckProject(projOptions) |> liftAsync// ParseAndCheckFileInProject(filename, 0, sourceText , projOptions) + + // if checkResults.Errors.Length > 0 then + // printfn "%A" checkResults.Errors + + // // Construct new typed parse result if the task succeeded + // match checkResults with + // | FSharpCheckProAnswer.Succeeded(checkResults) -> + // return! checkResults.GetAllUsesOfAllSymbolsInFile() + // | FSharpCheckFileAnswer.Aborted -> + // return Array.empty + + // let checkResult = languageService.GetCachedProjectCheckResult project + // match checkResult with + // | Some v -> let! allSymbols = v.GetAllUsesOfAllSymbols() + // return allSymbols |> Array.toSeq + // | None -> return Seq.empty + // with ex -> + // LoggingService.LogError("Global Search (F#) error", ex) + + // return Seq.empty } + + + //let getAllSymbolsInAllProjects() = + // asyncSeq { + // for projectFile in getAllFSharpProjects() do + // let! symbols = getAllProjectSymbols(projectFile) + // for symbol in symbols do + // yield symbol + // } + + /// constructors have a display name of ( .ctor ) use the enclosing entities display name +type ProjectSearchCategory() = + inherit SearchCategory(GettextCatalog.GetString ("Solution"), sortOrder = SearchCategory.FirstCategoryOrder) + + //type, module, struct, interface, enum, delegate, union, record + let typeTags = ["type"; "t"; "c"; "mod"; "s"; "i"; "e"; "d"; "u"; "r" ] + + //member, property, field, event, active pattern, operator + let memberTags = ["member"; "m"; "p"; "f"; "evt"; "ap"; "op"] + let tags = lazy (List.concat [typeTags; memberTags] |> List.toArray) + + override x.get_Tags() = tags.Force() + + override x.IsValidTag tag = + typeTags |> List.contains tag || memberTags |> List.contains tag + + override x.GetResults(callback, pattern, token) = + let optionsManager = CompositionManager.Instance.GetExportedValue() + GlobalSearch.getSymbolUsesInWorkspace optionsManager pattern callback token + |> RoslynHelpers.StartAsyncUnitAsTask token + + + //Task.Run( + // (fun () -> async { + // try + // //LoggingService.LogInfo(sprintf "F# Global Search: Getting all project symbols for %s" shortName ) + // do! GlobalSearch.getSymbolUsesInWorkspace optionsManager pattern callback token + + + // with ex -> + // LoggingService.LogError("F# Global Search error", ex) } |> Async.StartImmediate) , token ) |> startAs diff --git a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs index 22e770eddb8..5571bc17c09 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/InteractiveSession.fs @@ -104,6 +104,7 @@ type InteractiveSession(pathToExe) = |> Event.filter (fun de -> de.Data <> null) |> Event.add (fun de -> LoggingService.logDebug "Interactive: received %s" de.Data + Console.WriteLine de.Data match de.Data with | Image image -> imageReceivedEvent.Trigger image | ServerPrompt -> promptReady.Trigger() @@ -167,6 +168,7 @@ type InteractiveSession(pathToExe) = fsiProcess <- startProcess() member x.SendInput input documentName = + printfn "%s" input documentName |> Option.iter(fun fileName -> sendCommand (sprintf "input # 0 @\"%s\"" fileName)) From 9ec32c015e5d70844e21ba40e4cb68aa49385682 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 14 May 2020 12:07:09 +0100 Subject: [PATCH 096/101] Wire up global search --- vsintegration/src/FSharp.Editor/FSharp.addin.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index c9d7f3635fd..3b2884434b3 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -144,4 +144,7 @@ + + + From f8c61ef2b826e8b0f12d9341056c358b881ce503 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 14 May 2020 12:52:45 +0100 Subject: [PATCH 097/101] Clean up Global search --- .../src/FSharp.Editor/VSMac/GlobalSearch.fs | 58 +------------------ 1 file changed, 1 insertion(+), 57 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/VSMac/GlobalSearch.fs b/vsintegration/src/FSharp.Editor/VSMac/GlobalSearch.fs index 1ac50bff977..6803369b9b7 100644 --- a/vsintegration/src/FSharp.Editor/VSMac/GlobalSearch.fs +++ b/vsintegration/src/FSharp.Editor/VSMac/GlobalSearch.fs @@ -213,56 +213,10 @@ module GlobalSearch = for span in spans do let sr = SymbolSearchResult(pattern.Pattern, symbol.Symbol.DisplayName, rank, symbol, span) callback.ReportResult sr - //let distinctUses = uses |> Array.distinctBy (fun symbolUse -> symbolUse.RangeAlternate) - //return distinctUses - | None -> ()//return [||] + | None -> () }) |> Async.Parallel |> Async.Ignore - // FCS may return several `FSharpSymbolUse`s for same range, which have different `ItemOccurrence`s (Use, UseInAttribute, UseInType, etc.) - // We don't care about the occurrence type here, so we distinct by range. - //|> Async.map (Array.distinctBy (fun x -> x.RangeAlternate)) - - //let getAllProjectSymbols (project: Project) = - // asyncMaybe { - // try - // let filename = "test.fsx" - // let optionsManager = CompositionManager.Instance.GetExportedValue() - // let checker = optionsManager.Checker - // let! projectId = IdeApp.TypeSystemService.GetCodeAnalysisProjectAsync(project) |> liftTaskAsync - // let! parseResults , projOptions = optionsManager.TryGetOptionsByProject(projectId, Async.DefaultCancellationToken) - // //let sourceText = SourceText.ofString source - // //let! projOptions, _errors = checker.GetProjectOptions - // let! checkResults = checker.ParseAndCheckProject(projOptions) |> liftAsync// ParseAndCheckFileInProject(filename, 0, sourceText , projOptions) - - // if checkResults.Errors.Length > 0 then - // printfn "%A" checkResults.Errors - - // // Construct new typed parse result if the task succeeded - // match checkResults with - // | FSharpCheckProAnswer.Succeeded(checkResults) -> - // return! checkResults.GetAllUsesOfAllSymbolsInFile() - // | FSharpCheckFileAnswer.Aborted -> - // return Array.empty - - // let checkResult = languageService.GetCachedProjectCheckResult project - // match checkResult with - // | Some v -> let! allSymbols = v.GetAllUsesOfAllSymbols() - // return allSymbols |> Array.toSeq - // | None -> return Seq.empty - // with ex -> - // LoggingService.LogError("Global Search (F#) error", ex) - - // return Seq.empty } - - - //let getAllSymbolsInAllProjects() = - // asyncSeq { - // for projectFile in getAllFSharpProjects() do - // let! symbols = getAllProjectSymbols(projectFile) - // for symbol in symbols do - // yield symbol - // } /// constructors have a display name of ( .ctor ) use the enclosing entities display name type ProjectSearchCategory() = @@ -284,14 +238,4 @@ type ProjectSearchCategory() = let optionsManager = CompositionManager.Instance.GetExportedValue() GlobalSearch.getSymbolUsesInWorkspace optionsManager pattern callback token |> RoslynHelpers.StartAsyncUnitAsTask token - - - //Task.Run( - // (fun () -> async { - // try - // //LoggingService.LogInfo(sprintf "F# Global Search: Getting all project symbols for %s" shortName ) - // do! GlobalSearch.getSymbolUsesInWorkspace optionsManager pattern callback token - - // with ex -> - // LoggingService.LogError("F# Global Search error", ex) } |> Async.StartImmediate) , token ) |> startAs From d431c2c37b4655224a3e4a2840db455a9da09353 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 14 May 2020 12:54:12 +0100 Subject: [PATCH 098/101] Add editor context menu xml --- .../src/FSharp.Editor/FSharp.addin.xml | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index 3b2884434b3..5b19a61876f 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -147,4 +147,34 @@ + + + + + + + + + + + + + + + + + + + Context menu for fsi + + + + + + + + + + + From 5860c76a113a9ce81a15ee556d255cdd39cbd467 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 14 May 2020 15:43:16 +0100 Subject: [PATCH 099/101] FSharp-Editor depends on MonoDevelop.TextEditor --- vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs b/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs index 45cb96f5c9c..ffce9e1cdf8 100644 --- a/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs +++ b/vsintegration/src/FSharp.Editor/Properties/AddinInfo.fs @@ -12,4 +12,5 @@ open Mono.Addins [] [] +[] () \ No newline at end of file From e2fd8795fcdc988b42fbb77d107e0e7b300c9a95 Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 14 May 2020 15:43:47 +0100 Subject: [PATCH 100/101] Add send text and references commands to context menu --- .../src/FSharp.Editor/FSharp.addin.xml | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index 5b19a61876f..bc7c372065f 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -71,49 +71,52 @@ + --> - - + + defaultHandler="Microsoft.VisualStudio.FSharp.Editor.SendFile" /> - + defaultHandler="Microsoft.VisualStudio.FSharp.Editor.SendSelection" /> - + defaultHandler="Microsoft.VisualStudio.FSharp.Editor.SendLine" /> + + @@ -147,29 +151,28 @@ - - - - + + + + + + + - + Context menu for fsi - + From 0f2c6e00044b8a014b014a8d2ec5719d3a7869ef Mon Sep 17 00:00:00 2001 From: nosami Date: Thu, 14 May 2020 17:40:06 +0100 Subject: [PATCH 101/101] Add F# templates to FSharp.Editor addin --- .../src/FSharp.Editor/FSharp.Editor.fsproj | 5 +- .../src/FSharp.Editor/FSharp.addin.xml | 63 + .../VSMac/templates/AssemblyInfo.xft.xml | 45 + .../VSMac/templates/EmptyFSharpScript.xft.xml | 18 + .../templates/EmptyFSharpSignature.xft.xml | 22 + .../VSMac/templates/EmptyFSharpSource.xft.xml | 18 + .../VSMac/templates/FSharp-templates.xml | 462 ++++++++ .../templates/FSharpConsoleProject.xpt.xml | 51 + .../VSMac/templates/FSharpGtkProject.xpt.xml | 86 ++ .../templates/FSharpLibraryProject.xpt.xml | 55 + .../FSharpNUnitLibraryProject.xpt.xml | 58 + .../templates/FSharpNUnitTestType.xft.xml | 31 + .../templates/FSharpTutorialProject.xpt.xml | 1019 +++++++++++++++++ .../VSMac/templates/PortableLibrary.xpt.xml | 58 + .../templates/SharedAssetsProject.xpt.xml | 36 + .../VSMac/templates/templates.targets | 43 + 16 files changed, 2068 insertions(+), 2 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/AssemblyInfo.xft.xml create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/EmptyFSharpScript.xft.xml create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/EmptyFSharpSignature.xft.xml create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/EmptyFSharpSource.xft.xml create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/FSharp-templates.xml create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/FSharpConsoleProject.xpt.xml create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/FSharpGtkProject.xpt.xml create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/FSharpLibraryProject.xpt.xml create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/FSharpNUnitLibraryProject.xpt.xml create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/FSharpNUnitTestType.xft.xml create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/FSharpTutorialProject.xpt.xml create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/PortableLibrary.xpt.xml create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/SharedAssetsProject.xpt.xml create mode 100644 vsintegration/src/FSharp.Editor/VSMac/templates/templates.targets diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 35bc6d7680b..42b3fd27859 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -2,6 +2,7 @@ + Debug AnyCPU @@ -24,7 +25,7 @@ 3 ..\..\..\..\..\build\AddIns\FSharp.Editor\FSharp.Editor.XML false - --warnon:11111182 --subsystemversion:6.00 --simpleresolution --nocopyfsharpcore + --warnon:11111182 --subsystemversion:6.00 --simpleresolution true --publicsign ..\..\..\src\buildtools\keys\MSFT.snk @@ -208,7 +209,7 @@ False - + {27096E7F-C91C-4AC6-B289-6897A701DF21} diff --git a/vsintegration/src/FSharp.Editor/FSharp.addin.xml b/vsintegration/src/FSharp.Editor/FSharp.addin.xml index bc7c372065f..80e0659a514 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.addin.xml +++ b/vsintegration/src/FSharp.Editor/FSharp.addin.xml @@ -2,6 +2,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -180,4 +202,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/AssemblyInfo.xft.xml b/vsintegration/src/FSharp.Editor/VSMac/templates/AssemblyInfo.xft.xml new file mode 100644 index 00000000000..909fd3774e2 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/AssemblyInfo.xft.xml @@ -0,0 +1,45 @@ + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/EmptyFSharpScript.xft.xml b/vsintegration/src/FSharp.Editor/VSMac/templates/EmptyFSharpScript.xft.xml new file mode 100644 index 00000000000..430b9ab2be4 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/EmptyFSharpScript.xft.xml @@ -0,0 +1,18 @@ + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/EmptyFSharpSignature.xft.xml b/vsintegration/src/FSharp.Editor/VSMac/templates/EmptyFSharpSignature.xft.xml new file mode 100644 index 00000000000..8f6627dfeb9 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/EmptyFSharpSignature.xft.xml @@ -0,0 +1,22 @@ + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/EmptyFSharpSource.xft.xml b/vsintegration/src/FSharp.Editor/VSMac/templates/EmptyFSharpSource.xft.xml new file mode 100644 index 00000000000..ee9b706bb41 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/EmptyFSharpSource.xft.xml @@ -0,0 +1,18 @@ + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/FSharp-templates.xml b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharp-templates.xml new file mode 100644 index 00000000000..b88b14728e3 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharp-templates.xml @@ -0,0 +1,462 @@ + + + +
+ <_Group>F# + + text/x-fsharp + agent + <_Description>Creates boilerplate code for an agent + Unknown +
+ + + myAgent + + + string + + + (fun inbox -> + let rec loop () = + async { + let! msg = inbox.Receive() + return! loop () } + loop ()) +$end$]]> +
+ + +
+ <_Group>F# + + text/x-fsharp + outlet + <_Description>Creates an iOS outlet with attribute + Unknown +
+ + + Name + + + UILabel + + + ] +member val $name$ : $type$ = null with get, set]]> +
+ + +
+ <_Group>F# + + text/x-fsharp + action + <_Description>Creates an iOS action with attribute + Unknown +
+ + + Name + + + NSObject + + + ] +member this.$name$ (sender : $type$) = + $end$]]> +
+ + +
+ <_Group>F# + + text/x-fsharp + uncheck + <_Description>Creates an unchecked default value + Unknown +
+ + + type + + + ]]> +
+ + +
+ <_Group>F# + + text/x-fsharp + check + <_Description>Checks variable type + Expansion +
+ + + name + + + type + + + () +| _ -> ()]]> +
+ + +
+ <_Group>F# + + text/x-fsharp + virt + <_Description>Adds a virtual member + Expansion +
+ + + name + + + delta + + + unit +default this.$funName$ (delta:int) = ()]]> +
+ + +
+ <_Group>F# + + text/x-fsharp + abstract + <_Description>Creates an abstract method + Expansion +
+ + + name + + + parameters + + + +
+ + +
+ <_Group>F# + + text/x-fsharp + abstractp + <_Description>Creates an abstract property + Expansion +
+ + + name + + + int + + + +
+ + +
+ <_Group>F# + + text/x-fsharp + seq + <_Description>Creates a sequence + Unknown +
+ + +
+ + +
+ <_Group>F# + + text/x-fsharp + list + <_Description>Creates a list + Unknown +
+ + + name + + + +
+ + +
+ <_Group>F# + + text/x-fsharp + array + <_Description>Creates an array + Unknown +
+ + + name + + + +
+ + +
+ <_Group>F# + + text/x-fsharp + struct + <_Description>Creates a struct + Expansion +
+ + + name + + + ] +type $name$ = + $end$]]> +
+ + +
+ <_Group>F# + + text/x-fsharp + if + <_Description>Template for if...then + Expansion +
+ + + condition + + + +
+ + +
+ <_Group>F# + + text/x-fsharp + elif + <_Description>Template for elif...then + Expansion +
+ + + condition + + + +
+ + +
+ <_Group>F# + + text/x-fsharp + ifelse + <_Description>Template for if...then...else + Expansion +
+ + + condition + + + +
+ + +
+ <_Group>F# + + text/x-fsharp + while + <_Description>Template for while + Expansion +
+ + + condition + + + > +
+ + +
+ <_Group>F# + + text/x-fsharp + fort + <_Description>Template for for...to + Expansion +
+ + + identifier + + + start + + + finish + + + +
+ + +
+ <_Group>F# + + text/x-fsharp + fordt + <_Description>Template for for...downto + Expansion +
+ + + identifier + + + start + + + finish + + + +
+ + +
+ <_Group>F# + + text/x-fsharp + fori + <_Description>Template for for...in + Expansion +
+ + + pattern + + + expression + + + +
+ + +
+ <_Group>F# + + text/x-fsharp + match + <_Description>Template for match + Expansion +
+ + + expression + + + pattern + + + $end$]]> +
+ + +
+ <_Group>F# + + text/x-fsharp + fun + <_Description>Template for fun + Expansion +
+ + + () + + + expression + + + $expression$ $end$]]> +
+ + +
+ <_Group>F# + + text/x-fsharp + main + <_Description>Template for main + Expansion +
+ + + main + + + ] +let $name$ argv = + printfn "%A" argv + 0]]> +
+ + +
+ <_Group>F# + + text/x-fsharp + tomap + <_Description>Converts dictionary to F# map + Expansion +
+ + + toMap + + + ) = + dictionary + |> Seq.map (|KeyValue|) + |> Map.ofSeq +$end$]]> +
+
diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpConsoleProject.xpt.xml b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpConsoleProject.xpt.xml new file mode 100644 index 00000000000..aee501369cd --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpConsoleProject.xpt.xml @@ -0,0 +1,51 @@ + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpGtkProject.xpt.xml b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpGtkProject.xpt.xml new file mode 100644 index 00000000000..fc1a242bced --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpGtkProject.xpt.xml @@ -0,0 +1,86 @@ + + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpLibraryProject.xpt.xml b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpLibraryProject.xpt.xml new file mode 100644 index 00000000000..ad788321f02 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpLibraryProject.xpt.xml @@ -0,0 +1,55 @@ + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpNUnitLibraryProject.xpt.xml b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpNUnitLibraryProject.xpt.xml new file mode 100644 index 00000000000..b205419510a --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpNUnitLibraryProject.xpt.xml @@ -0,0 +1,58 @@ + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpNUnitTestType.xft.xml b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpNUnitTestType.xft.xml new file mode 100644 index 00000000000..a165d4888d6 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpNUnitTestType.xft.xml @@ -0,0 +1,31 @@ + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpTutorialProject.xpt.xml b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpTutorialProject.xpt.xml new file mode 100644 index 00000000000..865305b0929 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/FSharpTutorialProject.xpt.xml @@ -0,0 +1,1019 @@ + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/PortableLibrary.xpt.xml b/vsintegration/src/FSharp.Editor/VSMac/templates/PortableLibrary.xpt.xml new file mode 100644 index 00000000000..9ec8583bf10 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/PortableLibrary.xpt.xml @@ -0,0 +1,58 @@ + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/SharedAssetsProject.xpt.xml b/vsintegration/src/FSharp.Editor/VSMac/templates/SharedAssetsProject.xpt.xml new file mode 100644 index 00000000000..e2cfa1e9019 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/SharedAssetsProject.xpt.xml @@ -0,0 +1,36 @@ + + diff --git a/vsintegration/src/FSharp.Editor/VSMac/templates/templates.targets b/vsintegration/src/FSharp.Editor/VSMac/templates/templates.targets new file mode 100644 index 00000000000..d7130fbd765 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/VSMac/templates/templates.targets @@ -0,0 +1,43 @@ + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + \ No newline at end of file