@@ -20,6 +20,7 @@ open Microsoft.VisualStudio.Shell.Interop
2020open Microsoft.FSharp .Compiler
2121open Microsoft.FSharp .Compiler .Range
2222open Microsoft.FSharp .Compiler .SourceCodeServices
23+ open System.Runtime .Caching
2324
2425type internal FSharpCompletionProvider
2526 (
@@ -33,7 +34,8 @@ type internal FSharpCompletionProvider
3334 inherit CompletionProvider()
3435
3536 static let userOpName = " CompletionProvider"
36- static let declarationItemsCache = ConditionalWeakTable< string, FSharpDeclarationListItem>()
37+ // Save the backing data in a memory cache held in a sliding window
38+ static let declarationItemsCache = new MemoryCache( " FSharp.Editor." + userOpName)
3739 static let [<Literal>] NameInCodePropName = " NameInCode"
3840 static let [<Literal>] FullNamePropName = " FullName"
3941 static let [<Literal>] IsExtensionMemberPropName = " IsExtensionMember"
@@ -138,15 +140,15 @@ type internal FSharpCompletionProvider
138140
139141 let maxHints = if mruItems.Values.Count = 0 then 0 else Seq.max mruItems.Values
140142
141- sortedDeclItems |> Array.iteri ( fun number declItem ->
142- let glyph = Tokenizer.FSharpGlyphToRoslynGlyph ( declItem .Glyph, declItem .Accessibility)
143+ sortedDeclItems |> Array.iteri ( fun number declarationItem ->
144+ let glyph = Tokenizer.FSharpGlyphToRoslynGlyph ( declarationItem .Glyph, declarationItem .Accessibility)
143145 let name =
144- match declItem .NamespaceToOpen with
145- | Some namespaceToOpen -> sprintf " %s (open %s )" declItem .Name namespaceToOpen
146- | _ -> declItem .Name
146+ match declarationItem .NamespaceToOpen with
147+ | Some namespaceToOpen -> sprintf " %s (open %s )" declarationItem .Name namespaceToOpen
148+ | _ -> declarationItem .Name
147149
148150 let filterText =
149- match declItem .NamespaceToOpen, declItem .Name.Split '.' with
151+ match declarationItem .NamespaceToOpen, declarationItem .Name.Split '.' with
150152 // There is no namespace to open and the item name does not contain dots, so we don't need to pass special FilterText to Roslyn.
151153 | None, [|_|] -> null
152154 // Either we have a namespace to open ("DateTime (open System)") or item name contains dots ("Array.map"), or both.
@@ -155,39 +157,37 @@ type internal FSharpCompletionProvider
155157
156158 let completionItem =
157159 CommonCompletionItem.Create( name, glyph = Nullable glyph, rules = getRules(), filterText = filterText)
158- .AddProperty( FullNamePropName, declItem .FullName)
160+ .AddProperty( FullNamePropName, declarationItem .FullName)
159161
160162 let completionItem =
161- match declItem .Kind with
163+ match declarationItem .Kind with
162164 | CompletionItemKind.Method ( isExtension = true ) ->
163165 completionItem.AddProperty( IsExtensionMemberPropName, " " )
164166 | _ -> completionItem
165167
166168 let completionItem =
167- if name <> declItem .NameInCode then
168- completionItem.AddProperty( NameInCodePropName, declItem .NameInCode)
169+ if name <> declarationItem .NameInCode then
170+ completionItem.AddProperty( NameInCodePropName, declarationItem .NameInCode)
169171 else completionItem
170172
171173 let completionItem =
172- match declItem .NamespaceToOpen with
174+ match declarationItem .NamespaceToOpen with
173175 | Some ns -> completionItem.AddProperty( NamespaceToOpenPropName, ns)
174176 | None -> completionItem
175177
176178 let priority =
177- match mruItems.TryGetValue declItem .FullName with
179+ match mruItems.TryGetValue declarationItem .FullName with
178180 | true , hints -> maxHints - hints
179181 | _ -> number + maxHints + 1
180182
181183 let sortText = sprintf " %06d " priority
182184
183- //#if DEBUG
184- //Logging.Logging.logInfof "***** %s => %s" name sortText
185- //#endif
186-
187185 let completionItem = completionItem.WithSortText( sortText)
188186
189- declarationItemsCache.Remove( completionItem.DisplayText) |> ignore // clear out stale entries if they exist
190- declarationItemsCache.Add( completionItem.DisplayText, declItem)
187+ let key = completionItem.DisplayText
188+ let cacheItem = CacheItem( key, declarationItem)
189+ let policy = CacheItemPolicy( SlidingExpiration= DefaultTuning.PerDocumentSavedDataSlidingWindow)
190+ declarationItemsCache.Set( cacheItem, policy)
191191 results.Add( completionItem))
192192
193193 if results.Count > 0 && not declarations.IsForType && not declarations.IsError && List.isEmpty partialName.QualifyingIdents then
@@ -234,15 +234,15 @@ type internal FSharpCompletionProvider
234234
235235 override this.GetDescriptionAsync ( _ : Document , completionItem : Completion.CompletionItem , cancellationToken : CancellationToken ): Task < CompletionDescription > =
236236 async {
237- let exists , declarationItem = declarationItemsCache.TryGetValue ( completionItem.DisplayText)
238- if exists then
237+ match declarationItemsCache.Get ( completionItem.DisplayText) with
238+ | : ? FSharpDeclarationListItem as declarationItem ->
239239 let! description = declarationItem.StructuredDescriptionTextAsync
240240 let documentation = List()
241241 let collector = RoslynHelpers.CollectTaggedText documentation
242242 // mix main description and xmldoc by using one collector
243243 XmlDocumentation.BuildDataTipText( documentationBuilder, collector, collector, collector, collector, collector, description)
244244 return CompletionDescription.Create( documentation.ToImmutableArray())
245- else
245+ | _ ->
246246 return CompletionDescription.Empty
247247 } |> RoslynHelpers.StartAsyncAsTask cancellationToken
248248
0 commit comments