@@ -6,20 +6,17 @@ open System
66open System.Composition
77open System.Collections .Generic
88open System.Collections .Immutable
9- open System.Diagnostics
109open System.Threading
1110open System.Runtime .Caching
1211
1312open Microsoft.CodeAnalysis
1413open Microsoft.CodeAnalysis .Classification
15- open Microsoft.CodeAnalysis .Editor
16- open Microsoft.CodeAnalysis .Host .Mef
1714open Microsoft.CodeAnalysis .Text
1815open Microsoft.CodeAnalysis .ExternalAccess .FSharp .Classification
1916
20- open FSharp.Compiler .CodeAnalysis
2117open FSharp.Compiler .EditorServices
2218open FSharp.Compiler .Tokenization
19+ open CancellableTasks
2320open Microsoft.VisualStudio .FSharp .Editor .Telemetry
2421
2522// IEditorClassificationService is marked as Obsolete, but is still supported. The replacement (IClassificationService)
@@ -32,49 +29,11 @@ open Microsoft.VisualStudio.FSharp.Editor.Telemetry
3229type SemanticClassificationData = SemanticClassificationView
3330type SemanticClassificationLookup = IReadOnlyDictionary< int, ResizeArray< SemanticClassificationItem>>
3431
35- [<Sealed>]
36- type DocumentCache < 'Value when 'Value: not struct >() =
37- /// Anything under two seconds, the caching stops working, meaning it won't actually cache the item.
38- /// Two seconds is just enough to keep the data around long enough to handle a flood of a requests asking for the same data
39- /// in a short period of time.
40- [<Literal>]
41- let slidingExpirationSeconds = 2.
42-
43- let cache = new MemoryCache( " fsharp-cache" )
44-
45- let policy =
46- CacheItemPolicy( SlidingExpiration = TimeSpan.FromSeconds slidingExpirationSeconds)
47-
48- member _.TryGetValueAsync ( doc : Document ) =
49- async {
50- let! ct = Async.CancellationToken
51- let! currentVersion = doc.GetTextVersionAsync ct |> Async.AwaitTask
52-
53- match cache.Get( doc.Id.ToString()) with
54- | null -> return ValueNone
55- | : ? ( VersionStamp * 'Value ) as value ->
56- if fst value = currentVersion then
57- return ValueSome( snd value)
58- else
59- return ValueNone
60- | _ -> return ValueNone
61- }
62-
63- member _.SetAsync ( doc : Document , value : 'Value ) =
64- async {
65- let! ct = Async.CancellationToken
66- let! currentVersion = doc.GetTextVersionAsync ct |> Async.AwaitTask
67- cache.Set( doc.Id.ToString(), ( currentVersion, value), policy)
68- }
69-
70- interface IDisposable with
71-
72- member _.Dispose () = cache.Dispose()
73-
7432[<Export( typeof< IFSharpClassificationService>) >]
7533type internal FSharpClassificationService [<ImportingConstructor>] () =
7634
77- static let getLexicalClassifications ( filePath : string , defines , text : SourceText , textSpan : TextSpan , ct ) =
35+ static let getLexicalClassifications ( filePath : string , defines , text : SourceText , textSpan : TextSpan , ct : CancellationToken ) =
36+
7837 let text = text.GetSubText( textSpan)
7938 let result = ImmutableArray.CreateBuilder()
8039
@@ -144,8 +103,7 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
144103 | _ -> ()
145104
146105 static let toSemanticClassificationLookup ( d : SemanticClassificationData ) =
147- let lookup =
148- System.Collections.Generic.Dictionary< int, ResizeArray< SemanticClassificationItem>>()
106+ let lookup = Dictionary< int, ResizeArray< SemanticClassificationItem>>()
149107
150108 let f ( dataItem : SemanticClassificationItem ) =
151109 let items =
@@ -160,9 +118,10 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
160118
161119 d.ForEach( f)
162120
163- System. Collections.ObjectModel.ReadOnlyDictionary lookup :> IReadOnlyDictionary<_, _>
121+ Collections.ObjectModel.ReadOnlyDictionary lookup :> IReadOnlyDictionary<_, _>
164122
165- let semanticClassificationCache = new DocumentCache< SemanticClassificationLookup>()
123+ let semanticClassificationCache =
124+ new DocumentCache< SemanticClassificationLookup>( " fsharp-semantic-classification-cache" )
166125
167126 interface IFSharpClassificationService with
168127 // Do not perform classification if we don't have project options (#defines matter)
@@ -175,11 +134,13 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
175134 result : List < ClassifiedSpan >,
176135 cancellationToken : CancellationToken
177136 ) =
178- async {
137+ cancellableTask {
179138 use _logBlock = Logger.LogBlock( LogEditorFunctionId.Classification_ Syntactic)
180139
140+ let! cancellationToken = CancellableTask.getCurrentCancellationToken ()
141+
181142 let defines , langVersion = document.GetFSharpQuickDefinesAndLangVersion()
182- let! sourceText = document.GetTextAsync( cancellationToken) |> Async.AwaitTask
143+ let! sourceText = document.GetTextAsync( cancellationToken)
183144
184145 // For closed documents, only get classification for the text within the span.
185146 // This may be inaccurate for multi-line tokens such as string literals, but this is ok for now
@@ -198,7 +159,10 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
198159 TelemetryReporter.ReportSingleEventWithDuration( TelemetryEvents.AddSyntacticCalssifications, eventProps)
199160
200161 if not isOpenDocument then
201- result.AddRange( getLexicalClassifications ( document.FilePath, defines, sourceText, textSpan, cancellationToken))
162+ let classifiedSpans =
163+ getLexicalClassifications ( document.FilePath, defines, sourceText, textSpan, cancellationToken)
164+
165+ result.AddRange( classifiedSpans)
202166 else
203167 result.AddRange(
204168 Tokenizer.getClassifiedSpans (
@@ -212,7 +176,7 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
212176 )
213177 )
214178 }
215- |> RoslynHelpers.StartAsyncUnitAsTask cancellationToken
179+ |> CancellableTask.startAsTask cancellationToken
216180
217181 member _.AddSemanticClassificationsAsync
218182 (
@@ -221,10 +185,10 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
221185 result : List < ClassifiedSpan >,
222186 cancellationToken : CancellationToken
223187 ) =
224- async {
188+ cancellableTask {
225189 use _logBlock = Logger.LogBlock( LogEditorFunctionId.Classification_ Semantic)
226190
227- let! sourceText = document.GetTextAsync( cancellationToken) |> Async.AwaitTask
191+ let! sourceText = document.GetTextAsync( cancellationToken)
228192
229193 // If we are trying to get semantic classification for a document that is not open, get the results from the background and cache it.
230194 // We do this for find all references when it is populating results.
@@ -248,9 +212,11 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
248212
249213 addSemanticClassificationByLookup sourceText textSpan classificationDataLookup result
250214 | _ ->
251- let eventProps =
215+ let eventProps : ( string * obj ) array =
252216 [|
253- " isOpenDocument" , isOpenDocument :> obj
217+ " context.document.project.id" , document.Project.Id.Id.ToString()
218+ " context.document.id" , document.Id.Id.ToString()
219+ " isOpenDocument" , isOpenDocument
254220 " textSpanLength" , textSpan.Length
255221 " cacheHit" , false
256222 |]
@@ -283,8 +249,7 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
283249 let classificationData = checkResults.GetSemanticClassification( Some targetRange)
284250 addSemanticClassification sourceText textSpan classificationData result
285251 }
286- |> Async.Ignore
287- |> RoslynHelpers.StartAsyncUnitAsTask cancellationToken
252+ |> CancellableTask.startAsTask cancellationToken
288253
289254 // Do not perform classification if we don't have project options (#defines matter)
290255 member _.AdjustStaleClassification ( _ : SourceText , classifiedSpan : ClassifiedSpan ) : ClassifiedSpan = classifiedSpan
0 commit comments