Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use background CancellableTask in VS instead of async & asyncMaybe #15187

Merged
merged 28 commits into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7bbfbea
wip
vzarytovskii May 4, 2023
187ea2e
iteration
vzarytovskii May 5, 2023
4710007
iteration: quickinfo, help context
vzarytovskii May 5, 2023
350669e
fantomas
vzarytovskii May 5, 2023
4451bb6
Merge remote-tracking branch 'upstream/main' into cancellable-tasks
vzarytovskii May 5, 2023
0641626
todo
vzarytovskii May 5, 2023
ab022cb
Merge remote-tracking branch 'upstream/main' into cancellable-tasks
vzarytovskii May 9, 2023
9ad35fe
Merge remote-tracking branch 'upstream/main' into cancellable-tasks
vzarytovskii May 11, 2023
4440d4f
moved tasks to editor project, fixed comment colouring bug
vzarytovskii May 11, 2023
555fd73
fantomas
vzarytovskii May 11, 2023
206e9f3
Merge main
vzarytovskii May 18, 2023
418c79f
Fantomas + PR feedback
vzarytovskii May 18, 2023
bf51b31
Update vsintegration/src/FSharp.Editor/Hints/HintService.fs
vzarytovskii May 18, 2023
008df2b
Revert "Update vsintegration/src/FSharp.Editor/Hints/HintService.fs"
vzarytovskii May 19, 2023
ab459bf
Merge branch 'main' into cancellable-tasks
KevinRansom May 19, 2023
709563e
Update CancellableTasks.fs
vzarytovskii May 22, 2023
0838ced
Merge branch 'main' into cancellable-tasks
vzarytovskii May 23, 2023
20b4921
Added missing event properties for classifications event
vzarytovskii May 23, 2023
327b215
Added measurements for startup
vzarytovskii May 23, 2023
523f5ea
Automated command ran: fantomas
github-actions[bot] May 23, 2023
cdf5e5f
Added more settings for testing, added cache for hints
vzarytovskii May 24, 2023
3f4aa2b
Merge branch 'cancellable-tasks' of https://github.com/vzarytovskii/f…
vzarytovskii May 24, 2023
2ddefa6
Automated command ran: fantomas
github-actions[bot] May 24, 2023
4d93e72
Fix test
vzarytovskii May 25, 2023
295b090
Merge branch 'cancellable-tasks' of https://github.com/vzarytovskii/f…
vzarytovskii May 25, 2023
65ef0f5
fantomas
vzarytovskii May 25, 2023
c4d980f
Enable perf telemetry automatically with posibillity to opt out
vzarytovskii May 25, 2023
95b6cdc
Update vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
vzarytovskii May 25, 2023
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
2 changes: 1 addition & 1 deletion .fantomasignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ artifacts/
# For some reason, it tries to format files from remotes (Processing .\.git\refs\remotes\<remote>\FSComp.fsi)
.git/


# Explicitly unformatted implementation
src/Compiler/Checking/AccessibilityLogic.fs
src/Compiler/Checking/AttributeChecking.fs
Expand Down Expand Up @@ -98,6 +97,7 @@ src/Compiler/Service/IncrementalBuild.fs
src/Compiler/Service/ServiceAssemblyContent.fs
src/Compiler/Service/ServiceDeclarationLists.fs
src/Compiler/Service/ServiceErrorResolutionHints.fs
vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs

# Fantomas limitations on signature files (to investigate)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ open Microsoft.VisualStudio.Text.Classification
open Microsoft.VisualStudio.Utilities
open Microsoft.CodeAnalysis.Classification

open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.EditorServices

[<RequireQualifiedAccess>]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,17 @@ open System
open System.Composition
open System.Collections.Generic
open System.Collections.Immutable
open System.Diagnostics
open System.Threading
open System.Runtime.Caching

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 FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.EditorServices
open FSharp.Compiler.Tokenization
open CancellableTasks
open Microsoft.VisualStudio.FSharp.Editor.Telemetry

// IEditorClassificationService is marked as Obsolete, but is still supported. The replacement (IClassificationService)
Expand All @@ -46,9 +43,9 @@ type DocumentCache<'Value when 'Value: not struct>() =
CacheItemPolicy(SlidingExpiration = TimeSpan.FromSeconds slidingExpirationSeconds)

member _.TryGetValueAsync(doc: Document) =
async {
let! ct = Async.CancellationToken
let! currentVersion = doc.GetTextVersionAsync ct |> Async.AwaitTask
cancellableTask {
let! ct = CancellableTask.getCurrentCancellationToken ()
let! currentVersion = doc.GetTextVersionAsync ct

match cache.Get(doc.Id.ToString()) with
| null -> return ValueNone
Expand All @@ -61,9 +58,9 @@ type DocumentCache<'Value when 'Value: not struct>() =
}

member _.SetAsync(doc: Document, value: 'Value) =
async {
let! ct = Async.CancellationToken
let! currentVersion = doc.GetTextVersionAsync ct |> Async.AwaitTask
cancellableTask {
let! ct = CancellableTask.getCurrentCancellationToken ()
let! currentVersion = doc.GetTextVersionAsync ct
cache.Set(doc.Id.ToString(), (currentVersion, value), policy)
}

Expand All @@ -74,7 +71,8 @@ type DocumentCache<'Value when 'Value: not struct>() =
[<Export(typeof<IFSharpClassificationService>)>]
type internal FSharpClassificationService [<ImportingConstructor>] () =

static let getLexicalClassifications (filePath: string, defines, text: SourceText, textSpan: TextSpan, ct) =
static let getLexicalClassifications (filePath: string, defines, text: SourceText, textSpan: TextSpan, ct: CancellationToken) =

let text = text.GetSubText(textSpan)
let result = ImmutableArray.CreateBuilder()

Expand Down Expand Up @@ -144,8 +142,7 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
| _ -> ()

static let toSemanticClassificationLookup (d: SemanticClassificationData) =
let lookup =
System.Collections.Generic.Dictionary<int, ResizeArray<SemanticClassificationItem>>()
let lookup = Dictionary<int, ResizeArray<SemanticClassificationItem>>()

let f (dataItem: SemanticClassificationItem) =
let items =
Expand All @@ -160,7 +157,7 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =

d.ForEach(f)

System.Collections.ObjectModel.ReadOnlyDictionary lookup :> IReadOnlyDictionary<_, _>
Collections.ObjectModel.ReadOnlyDictionary lookup :> IReadOnlyDictionary<_, _>

let semanticClassificationCache = new DocumentCache<SemanticClassificationLookup>()

Expand All @@ -175,11 +172,13 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
result: List<ClassifiedSpan>,
cancellationToken: CancellationToken
) =
async {
cancellableTask {
use _logBlock = Logger.LogBlock(LogEditorFunctionId.Classification_Syntactic)

let! cancellationToken = CancellableTask.getCurrentCancellationToken ()

let defines, langVersion = document.GetFSharpQuickDefinesAndLangVersion()
let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
let! sourceText = document.GetTextAsync(cancellationToken)

// For closed documents, only get classification for the text within the span.
// This may be inaccurate for multi-line tokens such as string literals, but this is ok for now
Expand All @@ -198,7 +197,10 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
TelemetryReporter.ReportSingleEventWithDuration(TelemetryEvents.AddSyntacticCalssifications, eventProps)

if not isOpenDocument then
result.AddRange(getLexicalClassifications (document.FilePath, defines, sourceText, textSpan, cancellationToken))
let classifiedSpans =
getLexicalClassifications (document.FilePath, defines, sourceText, textSpan, cancellationToken)

result.AddRange(classifiedSpans)
else
result.AddRange(
Tokenizer.getClassifiedSpans (
Expand All @@ -212,7 +214,7 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
)
)
}
|> RoslynHelpers.StartAsyncUnitAsTask cancellationToken
|> CancellableTask.startAsTask cancellationToken

member _.AddSemanticClassificationsAsync
(
Expand All @@ -221,10 +223,10 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
result: List<ClassifiedSpan>,
cancellationToken: CancellationToken
) =
async {
cancellableTask {
use _logBlock = Logger.LogBlock(LogEditorFunctionId.Classification_Semantic)

let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
let! sourceText = document.GetTextAsync(cancellationToken)

// If we are trying to get semantic classification for a document that is not open, get the results from the background and cache it.
// We do this for find all references when it is populating results.
Expand Down Expand Up @@ -283,8 +285,7 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
let classificationData = checkResults.GetSemanticClassification(Some targetRange)
addSemanticClassification sourceText textSpan classificationData result
}
|> Async.Ignore
|> RoslynHelpers.StartAsyncUnitAsTask cancellationToken
|> CancellableTask.startAsTask cancellationToken

// Do not perform classification if we don't have project options (#defines matter)
member _.AdjustStaleClassification(_: SourceText, classifiedSpan: ClassifiedSpan) : ClassifiedSpan = classifiedSpan
39 changes: 22 additions & 17 deletions vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ open FSharp.Compiler.EditorServices
open FSharp.Compiler.Syntax
open FSharp.Compiler.Text
open Microsoft.CodeAnalysis
open CancellableTasks

[<Shared>]
[<ExportLanguageService(typeof<IHelpContextService>, FSharpConstants.FSharpLanguageName)>]
type internal FSharpHelpContextService [<ImportingConstructor>] () =

static member GetHelpTerm(document: Document, span: TextSpan, tokens: List<ClassifiedSpan>) : Async<string option> =
asyncMaybe {
let! _, check =
document.GetFSharpParseAndCheckResultsAsync(nameof (FSharpHelpContextService))
|> liftAsync
static member GetHelpTerm(document: Document, span: TextSpan, tokens: List<ClassifiedSpan>) : CancellableTask<string> =
cancellableTask {
let! cancellationToken = CancellableTask.getCurrentCancellationToken ()
let! _, check = document.GetFSharpParseAndCheckResultsAsync(nameof (FSharpHelpContextService))

let! sourceText = document.GetTextAsync() |> liftTaskAsync
let! sourceText = document.GetTextAsync(cancellationToken)
let textLines = sourceText.Lines
let lineInfo = textLines.GetLineFromPosition(span.Start)
let line = lineInfo.LineNumber
Expand Down Expand Up @@ -76,7 +76,7 @@ type internal FSharpHelpContextService [<ImportingConstructor>] () =
| otherwise -> otherwise, col

match tokenInformation with
| None -> return! None
| None -> return ""
| Some token ->
match token.ClassificationType with
| ClassificationTypeNames.Keyword
Expand All @@ -85,25 +85,31 @@ type internal FSharpHelpContextService [<ImportingConstructor>] () =
| ClassificationTypeNames.Comment -> return "comment_FS"
| ClassificationTypeNames.Identifier ->
try
let! (s, colAtEndOfNames, _) = QuickParse.GetCompleteIdentifierIsland false lineText col
let island = QuickParse.GetCompleteIdentifierIsland false lineText col

if check.HasFullTypeCheckInfo then
match island with
| Some (s, colAtEndOfNames, _) when check.HasFullTypeCheckInfo ->
let qualId = PrettyNaming.GetLongNameFromString s
return! check.GetF1Keyword(Line.fromZ line, colAtEndOfNames, lineText, qualId)
else
return! None

let f1Keyword =
check.GetF1Keyword(Line.fromZ line, colAtEndOfNames, lineText, qualId)

return Option.defaultValue "" f1Keyword

| _ -> return ""
with e ->
Assert.Exception e
return! None
| _ -> return! None
return ""
| _ -> return ""
}

interface IHelpContextService with
member this.Language = FSharpConstants.FSharpLanguageLongName
member this.Product = FSharpConstants.FSharpLanguageLongName

member this.GetHelpTermAsync(document, textSpan, cancellationToken) =
asyncMaybe {
cancellableTask {
let! cancellationToken = CancellableTask.getCurrentCancellationToken ()
let! sourceText = document.GetTextAsync(cancellationToken)
let defines, langVersion = document.GetFSharpQuickDefinesAndLangVersion()
let textLine = sourceText.Lines.GetLineFromPosition(textSpan.Start)
Expand All @@ -121,7 +127,6 @@ type internal FSharpHelpContextService [<ImportingConstructor>] () =

return! FSharpHelpContextService.GetHelpTerm(document, textSpan, classifiedSpans)
}
|> Async.map (Option.defaultValue "")
|> RoslynHelpers.StartAsyncAsTask cancellationToken
|> CancellableTask.start cancellationToken

member this.FormatSymbol(_symbol) = Unchecked.defaultof<_>
Loading