@@ -6,9 +6,11 @@ open System
66open System.Composition
77open System.Collections .Concurrent
88open System.Collections .Generic
9+ open System.Collections .Immutable
910open System.Threading
1011open System.Threading .Tasks
1112open System.Linq
13+ open System.Runtime .CompilerServices
1214
1315open Microsoft.CodeAnalysis
1416open Microsoft.CodeAnalysis .Completion
@@ -24,15 +26,21 @@ open Microsoft.CodeAnalysis.Text
2426open Microsoft.VisualStudio .FSharp .LanguageService
2527open Microsoft.VisualStudio .Text
2628open Microsoft.VisualStudio .Text .Tagging
29+ open Microsoft.VisualStudio .Shell
30+ open Microsoft.VisualStudio .Shell .Interop
2731
2832open Microsoft.FSharp .Compiler .Parser
2933open Microsoft.FSharp .Compiler .Range
3034open Microsoft.FSharp .Compiler .SourceCodeServices
3135
32- type internal FSharpCompletionProvider ( workspace : Workspace ) =
36+ type internal FSharpCompletionProvider ( workspace : Workspace , serviceProvider : SVsServiceProvider ) =
3337 inherit CompletionProvider()
3438
3539 let completionTriggers = [ '.' ]
40+ let declarationItemsCache = ConditionalWeakTable< string, FSharpDeclarationListItem>()
41+
42+ let xmlMemberIndexService = serviceProvider.GetService( typeof< IVsXMLMemberIndexService>) :?> IVsXMLMemberIndexService
43+ let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder( xmlMemberIndexService, serviceProvider.DTE)
3644
3745 override this.ShouldTriggerCompletion ( sourceText : SourceText , caretPosition : int , trigger : CompletionTrigger , _ : OptionSet ) =
3846 // Skip if we are at the start of a document
@@ -73,8 +81,42 @@ type internal FSharpCompletionProvider(workspace: Workspace) =
7381
7482 | None -> false
7583
76- override this.ProvideCompletionsAsync ( context : Microsoft.CodeAnalysis.Completion.CompletionContext ): Task =
77- Task.CompletedTask
84+ override this.ProvideCompletionsAsync ( context : Microsoft.CodeAnalysis.Completion.CompletionContext ) =
85+ let computation = async {
86+ match FSharpLanguageService.GetOptions( context.Document.Project.Id) with
87+ | Some( options) ->
88+ let! sourceText = context.Document.GetTextAsync( context.CancellationToken) |> Async.AwaitTask
89+ let! parseResults = FSharpChecker.Instance.ParseFileInProject( context.Document.FilePath, sourceText.ToString(), options)
90+ let! textVersion = context.Document.GetTextVersionAsync( context.CancellationToken) |> Async.AwaitTask
91+ let! checkFileAnswer = FSharpChecker.Instance.CheckFileInProject( parseResults, context.Document.FilePath, textVersion.GetHashCode(), sourceText.ToString(), options)
92+ let checkFileResults = match checkFileAnswer with
93+ | FSharpCheckFileAnswer.Aborted -> failwith " Compilation isn't complete yet"
94+ | FSharpCheckFileAnswer.Succeeded( results) -> results
95+
96+ let textLine = sourceText.Lines.GetLineFromPosition( context.Position)
97+ let textLineNumber = textLine.LineNumber + 1 // Roslyn line numbers are zero-based
98+ let qualifyingNames , partialName = QuickParse.GetPartialLongNameEx( textLine.ToString(), context.Position - textLine.Start - 1 )
99+ let! declarations = checkFileResults.GetDeclarationListInfo( Some( parseResults), textLineNumber, context.Position, textLine.ToString(), qualifyingNames, partialName)
78100
79- override this.GetDescriptionAsync ( document : Document , item : CompletionItem , cancellationToken : CancellationToken ) =
80- Task.FromResult( CompletionDescription.Empty)
101+ for declarationItem in declarations.Items do
102+ let completionItem = CompletionItem.Create( declarationItem.Name)
103+ declarationItemsCache.Add( completionItem.DisplayText, declarationItem)
104+ context.AddItem( completionItem)
105+ | None -> ()
106+ }
107+
108+ Task.Run( CommonRoslynHelpers.GetTaskAction( computation), context.CancellationToken)
109+
110+ override this.GetDescriptionAsync ( _ : Document , completionItem : CompletionItem , cancellationToken : CancellationToken ): Task < CompletionDescription > =
111+ let computation = async {
112+ let exists , declarationItem = declarationItemsCache.TryGetValue( completionItem.DisplayText)
113+ if exists then
114+ let! description = declarationItem.DescriptionTextAsync
115+ let datatipText = XmlDocumentation.BuildDataTipText( documentationBuilder, description)
116+ return CompletionDescription.FromText( datatipText)
117+ else
118+ return CompletionDescription.Empty
119+ }
120+
121+ Async.StartAsTask( computation, TaskCreationOptions.None, cancellationToken)
122+ .ContinueWith( CommonRoslynHelpers.GetCompletedTaskResult, cancellationToken)
0 commit comments