未验证 提交 7e4b03f1 编写于 作者: D Don Syme 提交者: GitHub

fix script editing perf (#10159)

Co-authored-by: NDon Syme <donsyme@fastmail.com>
上级 eb5cf1a6
......@@ -8,6 +8,7 @@ open System.Reflection
open System.Runtime.InteropServices
open Internal.Utilities.FSharpEnvironment
open Microsoft.FSharp.Reflection
open System.Collections.Concurrent
[<AutoOpen>]
module ReflectionHelper =
......@@ -88,19 +89,19 @@ type IResolveDependenciesResult =
abstract Success: bool
/// The resolution output log
abstract StdOut: string array
abstract StdOut: string[]
/// The resolution error log (* process stderror *)
abstract StdError: string array
abstract StdError: string[]
/// The resolution paths
abstract Resolutions: string seq
abstract Resolutions: seq<string>
/// The source code file paths
abstract SourceFiles: string seq
abstract SourceFiles: seq<string>
/// The roots to package directories
abstract Roots: string seq
abstract Roots: seq<string>
[<AllowNullLiteralAttribute>]
......@@ -326,6 +327,8 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr
None
managers
let cache = ConcurrentDictionary<_,IResolveDependenciesResult>(HashIdentity.Structural)
/// Returns a formatted error message for the host to presentconstruct with just nativeProbing handler
new (nativeProbingRoots: NativeResolutionProbe) =
new DependencyProvider(Unchecked.defaultof<AssemblyResolutionProbe>, nativeProbingRoots)
......@@ -390,20 +393,24 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr
[<Optional;DefaultParameterValue("")>]implicitIncludeDir: string,
[<Optional;DefaultParameterValue("")>]mainScriptName: string,
[<Optional;DefaultParameterValue("")>]fileName: string): IResolveDependenciesResult =
let key = (packageManager.Key, scriptExt, Seq.toArray packageManagerTextLines, executionTfm, executionRid, implicitIncludeDir, mainScriptName, fileName)
try
let executionRid =
if isNull executionRid then
RidHelpers.platformRid
else
executionRid
packageManager.ResolveDependencies(implicitIncludeDir, mainScriptName, fileName, scriptExt, packageManagerTextLines, executionTfm, executionRid)
with e ->
let e = stripTieWrapper e
let err, msg = (DependencyManager.SR.packageManagerError(e.Message))
reportError.Invoke(ErrorReportType.Error, err, msg)
ReflectionDependencyManagerProvider.MakeResultFromFields(false, arrEmpty, arrEmpty, seqEmpty, seqEmpty, seqEmpty)
cache.GetOrAdd(key, System.Func<_,_>(fun _ ->
try
let executionRid =
if isNull executionRid then
RidHelpers.platformRid
else
executionRid
packageManager.ResolveDependencies(implicitIncludeDir, mainScriptName, fileName, scriptExt, packageManagerTextLines, executionTfm, executionRid)
with e ->
let e = stripTieWrapper e
let err, msg = (DependencyManager.SR.packageManagerError(e.Message))
reportError.Invoke(ErrorReportType.Error, err, msg)
ReflectionDependencyManagerProvider.MakeResultFromFields(false, arrEmpty, arrEmpty, seqEmpty, seqEmpty, seqEmpty)
))
interface IDisposable with
......
......@@ -158,7 +158,7 @@ type internal FSharpClassificationService
asyncMaybe {
use _logBlock = Logger.LogBlock(LogEditorFunctionId.Classification_Semantic)
let! _, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken)
let! _, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken, userOpName)
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.
......
......@@ -96,7 +96,7 @@ type internal FSharpAddOpenCodeFixProvider
override __.RegisterCodeFixesAsync context : Task =
asyncMaybe {
let document = context.Document
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken)
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName)
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
let! _, parsedInput, checkResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName = userOpName)
let line = sourceText.Lines.GetLineFromPosition(context.Span.End)
......
......@@ -138,7 +138,7 @@ type internal FSharpImplementInterfaceCodeFixProvider
override __.RegisterCodeFixesAsync context : Task =
asyncMaybe {
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(context.Document, context.CancellationToken)
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(context.Document, context.CancellationToken, userOpName)
let cancellationToken = context.CancellationToken
let! sourceText = context.Document.GetTextAsync(cancellationToken)
let! _, parsedInput, checkFileResults = checker.ParseAndCheckDocument(context.Document, projectOptions, sourceText = sourceText, userOpName = userOpName)
......
......@@ -22,6 +22,7 @@ type internal FSharpRemoveUnusedOpensCodeFixProvider
projectInfoManager: FSharpProjectOptionsManager
) =
inherit CodeFixProvider()
let userOpName = "FSharpRemoveUnusedOpensCodeFixProvider"
let fixableDiagnosticIds = [FSharpIDEDiagnosticIds.RemoveUnnecessaryImportsDiagnosticId]
let createCodeFix (title: string, context: CodeFixContext) =
......@@ -32,7 +33,7 @@ type internal FSharpRemoveUnusedOpensCodeFixProvider
let document = context.Document
let! sourceText = document.GetTextAsync()
let checker = checkerProvider.Checker
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken)
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName)
let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document, projectOptions, checker)
let changes =
unusedOpens
......
......@@ -57,7 +57,7 @@ type internal FSharpRenameUnusedValueCodeFixProvider
// We have to use the additional check for backtickes because `IsOperatorOrBacktickedName` operates on display names
// where backtickes are replaced with parens.
if not (PrettyNaming.IsOperatorOrBacktickedName ident) && not (ident.StartsWith "``") then
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken)
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName)
let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName=userOpName)
let m = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, context.Span, sourceText)
let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
......
......@@ -33,7 +33,7 @@ type internal FSharpReplaceWithSuggestionCodeFixProvider
do! Option.guard settings.CodeFixes.SuggestNamesForErrors
let document = context.Document
let! _, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken)
let! _, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName)
let! parseFileResults, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName=userOpName)
// This is all needed to get a declaration list
......
......@@ -52,6 +52,7 @@ type internal FSharpCodeLensService
) as self =
let lineLens = codeLens
let userOpName = "FSharpCodeLensService"
let visit pos parseTree =
AstTraversal.Traverse(pos, parseTree, { new AstTraversal.AstVisitorBase<_>() with
......@@ -154,7 +155,7 @@ type internal FSharpCodeLensService
logInfof "Rechecking code due to buffer edit!"
#endif
let! document = workspace.CurrentSolution.GetDocument(documentId.Value) |> Option.ofObj
let! _, options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, bufferChangedCts.Token)
let! _, options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, bufferChangedCts.Token, userOpName)
let! _, parsedInput, checkFileResults = checker.ParseAndCheckDocument(document, options, "LineLens", allowStaleResults=true)
#if DEBUG
logInfof "Getting uses of all symbols!"
......
......@@ -98,7 +98,7 @@ type internal FSharpHelpContextService
member this.GetHelpTermAsync(document, textSpan, cancellationToken) =
asyncMaybe {
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync(cancellationToken)
let! textVersion = document.GetTextVersionAsync(cancellationToken)
let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document)
......
......@@ -67,7 +67,7 @@ type internal XmlDocCommandFilter
// XmlDocable line #1 are 1-based, editor is 0-based
let curLineNum = wpfTextView.Caret.Position.BufferPosition.GetContainingLine().LineNumber + 1
let! document = document.Value
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, CancellationToken.None)
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, CancellationToken.None, userOpName)
let! sourceText = document.GetTextAsync(CancellationToken.None)
let! parsedInput = checker.ParseDocument(document, parsingOptions, sourceText, userOpName)
let xmlDocables = XmlDocParser.getXmlDocables (sourceText.ToFSharpSourceText(), Some parsedInput)
......
......@@ -228,7 +228,7 @@ type internal FSharpCompletionProvider
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document)
do! Option.guard (CompletionUtils.shouldProvideCompletion(document.Id, document.FilePath, defines, sourceText, context.Position))
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken)
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName)
let! textVersion = context.Document.GetTextVersionAsync(context.CancellationToken)
let getAllSymbols(fileCheckResults: FSharpCheckFileResults) =
if settings.IntelliSense.IncludeSymbolsFromUnopenedNamespacesOrModules
......@@ -298,7 +298,7 @@ type internal FSharpCompletionProvider
let! sourceText = document.GetTextAsync(cancellationToken)
let textWithItemCommitted = sourceText.WithChanges(TextChange(item.Span, nameInCode))
let line = sourceText.Lines.GetLineFromPosition(item.Span.Start)
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! parsedInput = checker.ParseDocument(document, parsingOptions, sourceText, userOpName)
let fullNameIdents = fullName |> Option.map (fun x -> x.Split '.') |> Option.defaultValue [||]
......
......@@ -197,7 +197,7 @@ type internal FSharpSignatureHelpProvider
member this.GetItemsAsync(document, position, triggerInfo, cancellationToken) =
asyncMaybe {
try
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync(cancellationToken)
let! textVersion = document.GetTextVersionAsync(cancellationToken)
......
......@@ -44,7 +44,7 @@ type internal FSharpBreakpointResolutionService
interface IFSharpBreakpointResolutionService with
member this.ResolveBreakpointAsync(document: Document, textSpan: TextSpan, cancellationToken: CancellationToken): Task<FSharpBreakpointResolutionResult> =
asyncMaybe {
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync(cancellationToken)
let! range = FSharpBreakpointResolutionService.GetBreakpointLocation(checkerProvider.Checker, sourceText, document.Name, textSpan, parsingOptions)
let! span = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range)
......
......@@ -112,7 +112,7 @@ type internal FSharpDocumentDiagnosticAnalyzer [<ImportingConstructor>] () =
member this.AnalyzeSyntaxAsync(document: Document, cancellationToken: CancellationToken): Task<ImmutableArray<Diagnostic>> =
let projectInfoManager = getProjectInfoManager document
asyncMaybe {
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync(cancellationToken)
let! textVersion = document.GetTextVersionAsync(cancellationToken)
return!
......@@ -125,7 +125,7 @@ type internal FSharpDocumentDiagnosticAnalyzer [<ImportingConstructor>] () =
member this.AnalyzeSemanticsAsync(document: Document, cancellationToken: CancellationToken): Task<ImmutableArray<Diagnostic>> =
let projectInfoManager = getProjectInfoManager document
asyncMaybe {
let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken)
let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync(cancellationToken)
let! textVersion = document.GetTextVersionAsync(cancellationToken)
if document.Project.Name <> FSharpConstants.FSharpMiscellaneousFilesName || isScriptFile document.FilePath then
......
......@@ -41,7 +41,7 @@ type internal SimplifyNameDiagnosticAnalyzer [<ImportingConstructor>] () =
do! Option.guard document.FSharpOptions.CodeFixes.SimplifyName
do Trace.TraceInformation("{0:n3} (start) SimplifyName", DateTime.Now.TimeOfDay.TotalSeconds)
do! Async.Sleep DefaultTuning.SimplifyNameInitialDelay |> liftAsync
let! _parsingOptions, projectOptions = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! _parsingOptions, projectOptions = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! textVersion = document.GetTextVersionAsync(cancellationToken)
let textVersionHash = textVersion.GetHashCode()
let! _ = guard.WaitAsync(cancellationToken) |> Async.AwaitTask |> liftAsync
......
......@@ -31,7 +31,7 @@ type internal UnusedDeclarationsAnalyzer [<ImportingConstructor>] () =
do Trace.TraceInformation("{0:n3} (start) UnusedDeclarationsAnalyzer", DateTime.Now.TimeOfDay.TotalSeconds)
do! Async.Sleep DefaultTuning.UnusedDeclarationsAnalyzerInitialDelay |> liftAsync // be less intrusive, give other work priority most of the time
match! getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) with
match! getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) with
| (_parsingOptions, projectOptions) ->
let! sourceText = document.GetTextAsync()
let checker = getChecker document
......
......@@ -51,7 +51,7 @@ type internal UnusedOpensDiagnosticAnalyzer [<ImportingConstructor>] () =
asyncMaybe {
do Trace.TraceInformation("{0:n3} (start) UnusedOpensAnalyzer", DateTime.Now.TimeOfDay.TotalSeconds)
do! Async.Sleep DefaultTuning.UnusedOpensAnalyzerInitialDelay |> liftAsync // be less intrusive, give other work priority most of the time
let! _parsingOptions, projectOptions = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! _parsingOptions, projectOptions = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync()
let checker = getChecker document
let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document, projectOptions, checker)
......
......@@ -75,7 +75,7 @@ type internal FSharpDocumentHighlightsService [<ImportingConstructor>] (checkerP
interface IFSharpDocumentHighlightsService with
member __.GetDocumentHighlightsAsync(document, position, _documentsToSearch, cancellationToken) : Task<ImmutableArray<FSharpDocumentHighlights>> =
asyncMaybe {
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync(cancellationToken)
let! textVersion = document.GetTextVersionAsync(cancellationToken)
let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
......
......@@ -17,7 +17,7 @@ type internal FSharpBraceMatchingService
projectInfoManager: FSharpProjectOptionsManager
) =
static let defaultUserOpName = "BraceMatching"
static let userOpName = "BraceMatching"
static member GetBraceMatchingResult(checker: FSharpChecker, sourceText: SourceText, fileName, parsingOptions: FSharpParsingOptions, position: int, userOpName: string, [<Optional; DefaultParameterValue(false)>] forFormatting: bool) =
async {
......@@ -37,9 +37,9 @@ type internal FSharpBraceMatchingService
interface IFSharpBraceMatcher with
member this.FindBracesAsync(document, position, cancellationToken) =
asyncMaybe {
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync(cancellationToken)
let! (left, right) = FSharpBraceMatchingService.GetBraceMatchingResult(checkerProvider.Checker, sourceText, document.Name, parsingOptions, position, defaultUserOpName)
let! (left, right) = FSharpBraceMatchingService.GetBraceMatchingResult(checkerProvider.Checker, sourceText, document.Name, parsingOptions, position, userOpName)
let! leftSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, left)
let! rightSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, right)
return FSharpBraceMatchingResult(leftSpan, rightSpan)
......
......@@ -29,7 +29,7 @@ type internal FSharpEditorFormattingService
static let getIndentation (line : string) = line |> Seq.takeWhile ((=) ' ') |> Seq.length
static member GetFormattingChanges(documentId: DocumentId, sourceText: SourceText, filePath: string, checker: FSharpChecker, indentStyle: FormattingOptions.IndentStyle, options: (FSharpParsingOptions * FSharpProjectOptions) option, position: int) =
static member GetFormattingChanges(documentId: DocumentId, sourceText: SourceText, filePath: string, checker: FSharpChecker, indentStyle: FormattingOptions.IndentStyle, parsingOptions: FSharpParsingOptions, position: int) =
// Logic for determining formatting changes:
// If first token on the current line is a closing brace,
// match the indent with the indent on the line that opened it
......@@ -40,8 +40,6 @@ type internal FSharpEditorFormattingService
// (this is what C# does)
do! Option.guard (indentStyle = FormattingOptions.IndentStyle.Smart)
let! parsingOptions, _projectOptions = options
let line = sourceText.Lines.[sourceText.Lines.IndexOf position]
let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
......@@ -151,8 +149,8 @@ type internal FSharpEditorFormattingService
let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
let! options = document.GetOptionsAsync(cancellationToken) |> Async.AwaitTask
let indentStyle = options.GetOption(FormattingOptions.SmartIndent, FSharpConstants.FSharpLanguageName)
let! projectOptionsOpt = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! textChange = FSharpEditorFormattingService.GetFormattingChanges(document.Id, sourceText, document.FilePath, checkerProvider.Checker, indentStyle, projectOptionsOpt, position)
let parsingOptions = projectInfoManager.TryGetQuickParsingOptionsForEditingDocumentOrProject(document)
let! textChange = FSharpEditorFormattingService.GetFormattingChanges(document.Id, sourceText, document.FilePath, checkerProvider.Checker, indentStyle, parsingOptions, position)
return textChange |> Option.toList |> toIList
}
......@@ -162,12 +160,9 @@ type internal FSharpEditorFormattingService
let! options = document.GetOptionsAsync(cancellationToken) |> Async.AwaitTask
let tabSize = options.GetOption<int>(FormattingOptions.TabSize, FSharpConstants.FSharpLanguageName)
match! projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) with
| Some (parsingOptions, _) ->
let! textChanges = FSharpEditorFormattingService.GetPasteChanges(document.Id, sourceText, document.FilePath, settings.Formatting, tabSize, parsingOptions, currentClipboard, span)
return textChanges |> Option.defaultValue Seq.empty |> toIList
| None ->
return toIList Seq.empty
let parsingOptions = projectInfoManager.TryGetQuickParsingOptionsForEditingDocumentOrProject(document)
let! textChanges = FSharpEditorFormattingService.GetPasteChanges(document.Id, sourceText, document.FilePath, settings.Formatting, tabSize, parsingOptions, currentClipboard, span)
return textChanges |> Option.defaultValue Seq.empty |> toIList
}
interface IFSharpEditorFormattingService with
......
......@@ -61,7 +61,7 @@ type internal FSharpIndentationService
true
| _ -> false
static member GetDesiredIndentation(documentId: DocumentId, sourceText: SourceText, filePath: string, lineNumber: int, tabSize: int, indentStyle: FormattingOptions.IndentStyle, options: (FSharpParsingOptions * FSharpProjectOptions) option): Option<int> =
static member GetDesiredIndentation(documentId: DocumentId, sourceText: SourceText, filePath: string, lineNumber: int, tabSize: int, indentStyle: FormattingOptions.IndentStyle, parsingOptions: FSharpParsingOptions): Option<int> =
// Match indentation with previous line
let rec tryFindPreviousNonEmptyLine l =
......@@ -81,8 +81,6 @@ type internal FSharpIndentationService
|> Seq.takeWhile ((=) ' ')
|> Seq.length
let! parsingOptions, _ = options
// Only use smart indentation after tokens that need indentation
// if the option is enabled
return
......@@ -100,8 +98,8 @@ type internal FSharpIndentationService
let! options = document.GetOptionsAsync(cancellationToken) |> Async.AwaitTask
let tabSize = options.GetOption<int>(FormattingOptions.TabSize, FSharpConstants.FSharpLanguageName)
let indentStyle = options.GetOption(FormattingOptions.SmartIndent, FSharpConstants.FSharpLanguageName)
let! projectOptionsOpt = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let indent = FSharpIndentationService.GetDesiredIndentation(document.Id, sourceText, document.FilePath, lineNumber, tabSize, indentStyle, projectOptionsOpt)
let parsingOptions = projectInfoManager.TryGetQuickParsingOptionsForEditingDocumentOrProject(document)
let indent = FSharpIndentationService.GetDesiredIndentation(document.Id, sourceText, document.FilePath, lineNumber, tabSize, indentStyle, parsingOptions)
return
match indent with
| None -> Nullable()
......
......@@ -169,7 +169,7 @@ type internal InlineRenameService
interface IFSharpEditorInlineRenameService with
member __.GetRenameInfoAsync(document: Document, position: int, cancellationToken: CancellationToken) : Task<IFSharpInlineRenameInfo> =
asyncMaybe {
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync(cancellationToken)
let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
return! InlineRenameService.GetInlineRenameInfo(checkerProvider.Checker, projectInfoManager, document, sourceText, position, defines, projectOptions)
......
......@@ -75,7 +75,7 @@ module private FSharpProjectOptionsHelpers =
[<RequireQualifiedAccess>]
type private FSharpProjectOptionsMessage =
| TryGetOptionsByDocument of Document * AsyncReplyChannel<(FSharpParsingOptions * FSharpProjectOptions) option> * CancellationToken
| TryGetOptionsByDocument of Document * AsyncReplyChannel<(FSharpParsingOptions * FSharpProjectOptions) option> * CancellationToken * userOpName: string
| TryGetOptionsByProject of Project * AsyncReplyChannel<(FSharpParsingOptions * FSharpProjectOptions) option> * CancellationToken
| ClearOptions of ProjectId
| ClearSingleFileOptionsCache of DocumentId
......@@ -92,13 +92,13 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor
let cache = ConcurrentDictionary<ProjectId, Project * FSharpParsingOptions * FSharpProjectOptions>()
let singleFileCache = ConcurrentDictionary<DocumentId, VersionStamp * FSharpParsingOptions * FSharpProjectOptions>()
let rec tryComputeOptionsByFile (document: Document) (ct: CancellationToken) =
let rec tryComputeOptionsByFile (document: Document) (ct: CancellationToken) userOpName =
async {
let! fileStamp = document.GetTextVersionAsync(ct) |> Async.AwaitTask
match singleFileCache.TryGetValue(document.Id) with
| false, _ ->
let! sourceText = document.GetTextAsync(ct) |> Async.AwaitTask
let! scriptProjectOptions, _ = checkerProvider.Checker.GetProjectOptionsFromScript(document.FilePath, sourceText.ToFSharpSourceText(), SessionsProperties.fsiPreview)
let! scriptProjectOptions, _ = checkerProvider.Checker.GetProjectOptionsFromScript(document.FilePath, sourceText.ToFSharpSourceText(), SessionsProperties.fsiPreview, userOpName=userOpName)
let projectOptions =
if isScriptFile document.FilePath then
scriptProjectOptions
......@@ -129,7 +129,7 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor
| true, (fileStamp2, parsingOptions, projectOptions) ->
if fileStamp <> fileStamp2 then
singleFileCache.TryRemove(document.Id) |> ignore
return! tryComputeOptionsByFile document ct
return! tryComputeOptionsByFile document ct userOpName
else
return Some(parsingOptions, projectOptions)
}
......@@ -244,7 +244,7 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor
async {
while true do
match! agent.Receive() with
| FSharpProjectOptionsMessage.TryGetOptionsByDocument(document, reply, ct) ->
| FSharpProjectOptionsMessage.TryGetOptionsByDocument(document, reply, ct, userOpName) ->
if ct.IsCancellationRequested then
reply.Reply None
else
......@@ -253,7 +253,7 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor
if document.Project.Solution.Workspace.Kind = WorkspaceKind.MiscellaneousFiles then
reply.Reply None
elif document.Project.Name = FSharpConstants.FSharpMiscellaneousFilesName then
let! options = tryComputeOptionsByFile document ct
let! options = tryComputeOptionsByFile document ct userOpName
reply.Reply options
else
// We only care about the latest project in the workspace's solution.
......@@ -300,8 +300,8 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor
member __.TryGetOptionsByProjectAsync(project, ct) =
agent.PostAndAsyncReply(fun reply -> FSharpProjectOptionsMessage.TryGetOptionsByProject(project, reply, ct))
member __.TryGetOptionsByDocumentAsync(document, ct) =
agent.PostAndAsyncReply(fun reply -> FSharpProjectOptionsMessage.TryGetOptionsByDocument(document, reply, ct))
member __.TryGetOptionsByDocumentAsync(document, ct, userOpName) =
agent.PostAndAsyncReply(fun reply -> FSharpProjectOptionsMessage.TryGetOptionsByDocument(document, reply, ct, userOpName))
member __.ClearOptionsByProjectId(projectId) =
agent.Post(FSharpProjectOptionsMessage.ClearOptions(projectId))
......@@ -379,23 +379,29 @@ type internal FSharpProjectOptionsManager
reactor.TryGetOptionsByProjectAsync(project)
/// Get the exact options for a document or project
member this.TryGetOptionsForDocumentOrProject(document: Document, cancellationToken) =
member this.TryGetOptionsForDocumentOrProject(document: Document, cancellationToken, userOpName) =
async {
match! reactor.TryGetOptionsByDocumentAsync(document, cancellationToken) with
match! reactor.TryGetOptionsByDocumentAsync(document, cancellationToken, userOpName) with
| Some(parsingOptions, projectOptions) ->
return Some(parsingOptions, None, projectOptions)
| _ ->
return None
}
/// Get the options for a document or project relevant for syntax processing.
/// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project options for a script.
member this.TryGetOptionsForEditingDocumentOrProject(document:Document, cancellationToken) =
/// Get the exact options for a document or project relevant for syntax processing.
member this.TryGetOptionsForEditingDocumentOrProject(document:Document, cancellationToken, userOpName) =
async {
let! result = this.TryGetOptionsForDocumentOrProject(document, cancellationToken)
let! result = this.TryGetOptionsForDocumentOrProject(document, cancellationToken, userOpName)
return result |> Option.map(fun (parsingOptions, _, projectOptions) -> parsingOptions, projectOptions)
}
/// Get the options for a document or project relevant for syntax processing.
/// Quicker it doesn't need to recompute the exact project options for a script.
member this.TryGetQuickParsingOptionsForEditingDocumentOrProject(document:Document) =
match reactor.TryGetCachedOptionsByProjectId(document.Project.Id) with
| Some (_, parsingOptions, _) -> parsingOptions
| _ -> { FSharpParsingOptions.Default with IsInteractive = FSharpFileUtilities.isScriptFile document.Name }
[<Export>]
/// This handles commandline change notifications from the Dotnet Project-system
/// Prior to VS 15.7 path contained path to project file, post 15.7 contains target binpath
......
......@@ -25,7 +25,7 @@ module internal SymbolHelpers =
let textLine = sourceText.Lines.GetLineFromPosition(position)
let textLinePos = sourceText.Lines.GetLinePosition(position)
let fcsTextLineNumber = Line.fromZ textLinePos.Line
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false)
let settings = document.FSharpOptions
......@@ -118,7 +118,7 @@ module internal SymbolHelpers =
let! sourceText = document.GetTextAsync(cancellationToken)
let originalText = sourceText.ToString(symbolSpan)
do! Option.guard (originalText.Length > 0)
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, symbolSpan.Start, document.FilePath, defines, SymbolLookupKind.Greedy, false)
let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName = userOpName)
......
......@@ -51,7 +51,7 @@ type internal FSharpFindUsagesService
asyncMaybe {
let! sourceText = document.GetTextAsync(context.CancellationToken) |> Async.AwaitTask |> liftAsync
let checker = checkerProvider.Checker
let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, context.CancellationToken)
let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, context.CancellationToken, userOpName)
let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName = userOpName)
let textLine = sourceText.Lines.GetLineFromPosition(position).ToString()
let lineNumber = sourceText.Lines.GetLinePosition(position).Line + 1
......
......@@ -168,7 +168,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP
/// Helper function that is used to determine the navigation strategy to apply, can be tuned towards signatures or implementation files.
member private __.FindSymbolHelper (originDocument: Document, originRange: range, sourceText: SourceText, preferSignature: bool) =
asyncMaybe {
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(originDocument, CancellationToken.None)
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(originDocument, CancellationToken.None, userOpName)
let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
let! originTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sourceText, originRange)
let position = originTextSpan.Start
......@@ -190,7 +190,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP
if not (File.Exists fsfilePath) then return! None else
let! implDoc = originDocument.Project.Solution.TryGetDocumentFromPath fsfilePath
let! implSourceText = implDoc.GetTextAsync ()
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(implDoc, CancellationToken.None)
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(implDoc, CancellationToken.None, userOpName)
let! _, _, checkFileResults = checker.ParseAndCheckDocument (implDoc, projectOptions, sourceText=implSourceText, userOpName=userOpName)
let! symbolUses = checkFileResults.GetUsesOfSymbolInFile symbol |> liftAsync
let! implSymbol = symbolUses |> Array.tryHead
......@@ -220,7 +220,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP
member private this.FindDefinitionAtPosition(originDocument: Document, position: int) =
asyncMaybe {
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(originDocument, CancellationToken.None)
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(originDocument, CancellationToken.None, userOpName)
let! sourceText = originDocument.GetTextAsync () |> liftTaskAsync
let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
let textLine = sourceText.Lines.GetLineFromPosition position
......@@ -307,7 +307,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP
let! implDocument = originDocument.Project.Solution.TryGetDocumentFromPath implFilePath
let! implVersion = implDocument.GetTextVersionAsync () |> liftTaskAsync
let! implSourceText = implDocument.GetTextAsync () |> liftTaskAsync
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(implDocument, CancellationToken.None)
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(implDocument, CancellationToken.None, userOpName)
let! targetRange = this.FindSymbolDeclarationInFile(targetSymbolUse, implFilePath, implSourceText, projectOptions, implVersion.GetHashCode())
......
......@@ -172,6 +172,7 @@ type internal FSharpNavigateToSearchService
projectInfoManager: FSharpProjectOptionsManager
) =
let userOpName = "FSharpNavigateToSearchService"
let kindsProvided = ImmutableHashSet.Create(FSharpNavigateToItemKind.Module, FSharpNavigateToItemKind.Class, FSharpNavigateToItemKind.Field, FSharpNavigateToItemKind.Property, FSharpNavigateToItemKind.Method, FSharpNavigateToItemKind.Enum, FSharpNavigateToItemKind.EnumItem) :> IImmutableSet<string>
// Save the backing navigation data in a memory cache held in a sliding window
......@@ -261,7 +262,7 @@ type internal FSharpNavigateToSearchService
member __.SearchDocumentAsync(document, searchPattern, kinds, cancellationToken) : Task<ImmutableArray<FSharpNavigateToSearchResult>> =
asyncMaybe {
let! parsingOptions, _, _ = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken)
let! parsingOptions, _, _ = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken, userOpName)
let! items = getCachedIndexedNavigableItems(document, parsingOptions, kinds) |> liftAsync
return items.Find(searchPattern)
}
......
......@@ -32,7 +32,7 @@ type internal FSharpNavigationBarItemService
interface IFSharpNavigationBarItemService with
member __.GetItemsAsync(document, cancellationToken) : Task<IList<FSharpNavigationBarItem>> =
asyncMaybe {
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync(cancellationToken)
let! parsedInput = checkerProvider.Checker.ParseDocument(document, parsingOptions, sourceText=sourceText, userOpName=userOpName)
let navItems = FSharpNavigation.getNavigation parsedInput
......
......@@ -92,7 +92,7 @@ module internal FSharpQuickInfo =
asyncMaybe {
let! sourceText = document.GetTextAsync cancellationToken
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
let! lexerSymbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, true)
let idRange = lexerSymbol.Ident.idRange
......
......@@ -152,7 +152,7 @@ type internal FSharpBlockStructureService [<ImportingConstructor>] (checkerProvi
member __.GetBlockStructureAsync(document, cancellationToken) : Task<FSharpBlockStructure> =
asyncMaybe {
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken)
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync(cancellationToken)
let! parsedInput = checkerProvider.Checker.ParseDocument(document, parsingOptions, sourceText, userOpName)
return createBlockSpans document.FSharpOptions.Advanced.IsBlockStructureEnabled sourceText parsedInput |> Seq.toImmutableArray
......
......@@ -78,7 +78,7 @@ marker4"""
let lineNumber = sourceText.Lines |> Seq.findIndex (fun line -> line.Span.Contains position)
let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions
let changesOpt = FSharpEditorFormattingService.GetFormattingChanges(documentId, sourceText, filePath, checker, indentStyle, Some (parsingOptions, projectOptions), position) |> Async.RunSynchronously
let changesOpt = FSharpEditorFormattingService.GetFormattingChanges(documentId, sourceText, filePath, checker, indentStyle, parsingOptions, position) |> Async.RunSynchronously
match changesOpt with
| None -> Assert.Fail("Expected a text change, but got None")
| Some changes ->
......
......@@ -176,7 +176,7 @@ while true do
let sourceText = SourceText.From(template)
let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions
let actualIndentation = FSharpIndentationService.GetDesiredIndentation(documentId, sourceText, filePath, lineNumber, tabSize, indentStyle, Some (parsingOptions, projectOptions))
let actualIndentation = FSharpIndentationService.GetDesiredIndentation(documentId, sourceText, filePath, lineNumber, tabSize, indentStyle, parsingOptions)
match expectedIndentation with
| None -> Assert.IsTrue(actualIndentation.IsNone, "No indentation was expected at line {0}", lineNumber)
| Some indentation -> Assert.AreEqual(expectedIndentation.Value, actualIndentation.Value, "Indentation on line {0} doesn't match", lineNumber)
......@@ -189,7 +189,7 @@ while true do
let sourceText = SourceText.From(template)
let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions
let actualIndentation = FSharpIndentationService.GetDesiredIndentation(documentId, sourceText, filePath, lineNumber, tabSize, indentStyle, Some (parsingOptions, projectOptions))
let actualIndentation = FSharpIndentationService.GetDesiredIndentation(documentId, sourceText, filePath, lineNumber, tabSize, indentStyle, parsingOptions)
match expectedIndentation with
| None -> Assert.IsTrue(actualIndentation.IsNone, "No indentation was expected at line {0}", lineNumber)
| Some indentation -> Assert.AreEqual(expectedIndentation.Value, actualIndentation.Value, "Indentation on line {0} doesn't match", lineNumber)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册