Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes/.VisualStudio/18.vNext.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

* Fixed Rename incorrectly renaming `get` and `set` keywords for properties with explicit accessors. ([Issue #18270](https://github.com/dotnet/fsharp/issues/18270), [PR #19252](https://github.com/dotnet/fsharp/pull/19252))
* Fixed Find All References crash when F# project contains non-F# files like `.cshtml`. ([Issue #16394](https://github.com/dotnet/fsharp/issues/16394), [PR #19252](https://github.com/dotnet/fsharp/pull/19252))
* Avoid using `cancellableTask` in `DocumentCache`; the editor cache now uses direct `CancellationToken`-aware `task` wrappers, avoiding the background `Task.Run` offload and a larger wrapper closure from the `cancellableTask` builder. ([Issue #20268](https://github.com/dotnet/fsharp/issues/20268))
* Find All References for external DLL symbols now only searches projects that reference the specific assembly. ([Issue #10227](https://github.com/dotnet/fsharp/issues/10227), [PR #19252](https://github.com/dotnet/fsharp/pull/19252))
* Improve static compilation of state machines. ([PR #19297](https://github.com/dotnet/fsharp/pull/19297))
* Make Alt+F1 (momentary toggle) work for inlay hints. ([PR #19421](https://github.com/dotnet/fsharp/pull/19421))
Expand Down
54 changes: 33 additions & 21 deletions vsintegration/src/FSharp.Editor/Common/DocumentCache.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ namespace Microsoft.VisualStudio.FSharp.Editor

open System
open System.Runtime.Caching
open System.Threading
open System.Threading.Tasks
open Microsoft.CodeAnalysis
open CancellableTasks

Expand All @@ -16,30 +18,40 @@ type DocumentCache<'Value when 'Value: not struct>(name: string, ?cacheItemPolic
let policy =
defaultArg cacheItemPolicy (CacheItemPolicy(SlidingExpiration = (TimeSpan.FromSeconds defaultSlidingExpiration)))

static let tryGetCachedValueAsync (doc: Document, cache: MemoryCache, ct: CancellationToken) =
if ct.IsCancellationRequested then
Task.FromCanceled<'Value voption>(ct)
else
task {
let! currentVersion = doc.GetTextVersionAsync ct

match cache.Get(doc.Id.ToString()) with
| null -> return ValueNone
| :? (VersionStamp * 'Value) as value ->
if fst value = currentVersion then
return ValueSome(snd value)
else
return ValueNone
| _ -> return ValueNone
}

static let setCacheValueAsync (doc: Document, value: 'Value, cache: MemoryCache, policy: CacheItemPolicy, ct: CancellationToken) =
if ct.IsCancellationRequested then
Task.FromCanceled<unit>(ct)
else
task {
let! currentVersion = doc.GetTextVersionAsync ct
do cache.Set(doc.Id.ToString(), (currentVersion, value), policy)
}

new(name: string, slidingExpirationSeconds: float) =
new DocumentCache<'Value>(name, CacheItemPolicy(SlidingExpiration = (TimeSpan.FromSeconds slidingExpirationSeconds)))

member _.TryGetValueAsync(doc: Document) =
cancellableTask {
let! ct = CancellableTask.getCancellationToken ()
let! currentVersion = doc.GetTextVersionAsync ct

match cache.Get(doc.Id.ToString()) with
| null -> return ValueNone
| :? (VersionStamp * 'Value) as value ->
if fst value = currentVersion then
return ValueSome(snd value)
else
return ValueNone
| _ -> return ValueNone
}

member _.SetAsync(doc: Document, value: 'Value) =
cancellableTask {
let! ct = CancellableTask.getCancellationToken ()
let! currentVersion = doc.GetTextVersionAsync ct
do cache.Set(doc.Id.ToString(), (currentVersion, value), policy)
}
member _.TryGetValueAsync(doc: Document) : CancellableTask<'Value voption> =
fun ct -> tryGetCachedValueAsync (doc, cache, ct)

member _.SetAsync(doc: Document, value: 'Value) : CancellableTask<unit> =
fun ct -> setCacheValueAsync (doc, value, cache, policy, ct)

interface IDisposable with
member _.Dispose() = cache.Dispose()
Loading