Skip to content

Commit

Permalink
react to events #1
Browse files Browse the repository at this point in the history
  • Loading branch information
dsyme authored and dsyme committed Nov 27, 2016
1 parent 1cb58c6 commit 5694c6b
Show file tree
Hide file tree
Showing 20 changed files with 178 additions and 69 deletions.
16 changes: 8 additions & 8 deletions src/fsharp/vs/IncrementalBuild.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1272,10 +1272,10 @@ type IncrementalBuilder(frameworkTcImportsCache: FrameworkImportsCache, tcConfig

let tcConfigP = TcConfigProvider.Constant(tcConfig)
let importsInvalidated = new Event<string>()
let fileParsed = new Event<_>()
let beforeTypeCheckFile = new Event<_>()
let fileChecked = new Event<_>()
let projectChecked = new Event<_>()
let fileParsed = new Event<string>()
let beforeFileChecked = new Event<string>()
let fileChecked = new Event<string>()
let projectChecked = new Event<unit>()

// Resolve assemblies and create the framework TcImports. This is done when constructing the
// builder itself, rather than as an incremental task. This caches a level of "system" references. No type providers are
Expand Down Expand Up @@ -1361,7 +1361,7 @@ type IncrementalBuilder(frameworkTcImportsCache: FrameworkImportsCache, tcConfig
try
IncrementalBuilderEventTesting.MRU.Add(IncrementalBuilderEventTesting.IBEParsed filename)
let result = ParseOneInputFile(tcConfig,lexResourceManager, [], filename ,isLastCompiland,errorLogger,(*retryLocked*)true)
fileParsed.Trigger filename
fileParsed.Trigger (filename)
result,sourceRange,filename,errorLogger.GetErrors ()
with exn ->
System.Diagnostics.Debug.Assert(false, sprintf "unexpected failure in IncrementalFSharpBuild.Parse\nerror = %s" (exn.ToString()))
Expand Down Expand Up @@ -1457,7 +1457,7 @@ type IncrementalBuilder(frameworkTcImportsCache: FrameworkImportsCache, tcConfig
let errorLogger = GetErrorLoggerFilteringByScopedPragmas(false,GetScopedPragmasForInput(input),capturingErrorLogger)
let fullComputation =
eventually {
beforeTypeCheckFile.Trigger filename
beforeFileChecked.Trigger (filename)

ApplyMetaCommandsFromInputToTcConfig tcConfig (input, Path.GetDirectoryName filename) |> ignore
let sink = TcResultsSinkImpl(tcAcc.tcGlobals)
Expand All @@ -1475,7 +1475,7 @@ type IncrementalBuilder(frameworkTcImportsCache: FrameworkImportsCache, tcConfig
let typedImplFiles = if keepAssemblyContents then typedImplFiles else []
let tcResolutions = if keepAllBackgroundResolutions then sink.GetResolutions() else TcResolutions.Empty
let tcSymbolUses = sink.GetSymbolUses()
fileChecked.Trigger filename
fileChecked.Trigger (filename)
return {tcAcc with tcState=tcState
tcEnvAtEndOfFile=tcEnvAtEndOfFile
topAttribs=Some topAttribs
Expand Down Expand Up @@ -1656,7 +1656,7 @@ type IncrementalBuilder(frameworkTcImportsCache: FrameworkImportsCache, tcConfig

member __.TcConfig = tcConfig
member __.FileParsed = fileParsed.Publish
member __.BeforeTypeCheckFile = beforeTypeCheckFile.Publish
member __.BeforeFileChecked = beforeFileChecked.Publish
member __.FileChecked = fileChecked.Publish
member __.ProjectChecked = projectChecked.Publish
member __.ImportedCcusInvalidated = importsInvalidated.Publish
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/vs/IncrementalBuild.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ type internal IncrementalBuilder =
/// Raised just before a file is type-checked, to invalidate the state of the file in VS and force VS to request a new direct typecheck of the file.
/// The incremental builder also typechecks the file (error and intellisense results from the backgroud builder are not
/// used by VS).
member BeforeTypeCheckFile : IEvent<string>
member BeforeFileChecked : IEvent<string>

/// Raised just after a file is parsed
member FileParsed : IEvent<string>
Expand Down
29 changes: 16 additions & 13 deletions src/fsharp/vs/service.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1732,6 +1732,7 @@ type FSharpProjectOptions =
UseScriptResolutionRules : bool
LoadTime : System.DateTime
UnresolvedReferences : UnresolvedReferencesSet option
ExtraProjectInfo : obj option
}
member x.ProjectOptions = x.OtherOptions
/// Whether the two parse options refer to the same project.
Expand Down Expand Up @@ -2048,10 +2049,10 @@ module Helpers =
type BackgroundCompiler(referenceResolver, projectCacheSize, keepAssemblyContents, keepAllBackgroundResolutions) as self =
// STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.backgroundCompiler.reactor: The one and only Reactor
let reactor = Reactor.Singleton
let beforeFileChecked = Event<string>()
let fileParsed = Event<string>()
let fileChecked = Event<string>()
let projectChecked = Event<string>()
let beforeFileChecked = Event<string * obj option>()
let fileParsed = Event<string * obj option>()
let fileChecked = Event<string * obj option>()
let projectChecked = Event<string * obj option>()

let mutable implicitlyStartBackgroundWork = true
let reactorOps =
Expand Down Expand Up @@ -2105,10 +2106,10 @@ type BackgroundCompiler(referenceResolver, projectCacheSize, keepAssemblyContent
//
// This indicates to the UI that the file type check state is dirty. If the file is open and visible then
// the UI will sooner or later request a typecheck of the file, recording errors and intellisense information.
builder.BeforeTypeCheckFile.Add (beforeFileChecked.Trigger)
builder.FileParsed.Add (fileParsed.Trigger)
builder.FileChecked.Add (fileChecked.Trigger)
builder.ProjectChecked.Add (fun () -> projectChecked.Trigger options.ProjectFileName)
builder.BeforeFileChecked.Add (fun file -> beforeFileChecked.Trigger(file, options.ExtraProjectInfo))
builder.FileParsed.Add (fun file -> fileParsed.Trigger(file, options.ExtraProjectInfo))
builder.FileChecked.Add (fun file -> fileChecked.Trigger(file, options.ExtraProjectInfo))
builder.ProjectChecked.Add (fun () -> projectChecked.Trigger (options.ProjectFileName, options.ExtraProjectInfo))

(builderOpt, errorsAndWarnings, decrement)

Expand Down Expand Up @@ -2438,7 +2439,7 @@ type BackgroundCompiler(referenceResolver, projectCacheSize, keepAssemblyContent
member bc.ParseAndCheckProject(options) =
reactor.EnqueueAndAwaitOpAsync("ParseAndCheckProject " + options.ProjectFileName, fun ct -> bc.ParseAndCheckProjectImpl(options, ct))

member bc.GetProjectOptionsFromScript(filename, source, ?loadedTimeStamp, ?otherFlags, ?useFsiAuxLib, ?assumeDotNetFramework) =
member bc.GetProjectOptionsFromScript(filename, source, ?loadedTimeStamp, ?otherFlags, ?useFsiAuxLib, ?assumeDotNetFramework, ?extraProjectInfo: obj) =
reactor.EnqueueAndAwaitOpAsync ("GetProjectOptionsFromScript " + filename, fun _ct ->
// Do we add a reference to FSharp.Compiler.Interactive.Settings by default?
let useFsiAuxLib = defaultArg useFsiAuxLib true
Expand Down Expand Up @@ -2473,6 +2474,7 @@ type BackgroundCompiler(referenceResolver, projectCacheSize, keepAssemblyContent
UseScriptResolutionRules = true
LoadTime = loadedTimeStamp
UnresolvedReferences = Some (UnresolvedReferencesSet(fas.UnresolvedReferences))
ExtraProjectInfo=extraProjectInfo
}
scriptClosureCache.Set(co,fas) // Save the full load closure for later correlation.
co)
Expand Down Expand Up @@ -2664,10 +2666,10 @@ type FSharpChecker(referenceResolver, projectCacheSize, keepAssemblyContents, ke
backgroundCompiler.KeepProjectAlive(options)

/// For a given script file, get the ProjectOptions implied by the #load closure
member ic.GetProjectOptionsFromScript(filename, source, ?loadedTimeStamp, ?otherFlags, ?useFsiAuxLib) =
backgroundCompiler.GetProjectOptionsFromScript(filename,source,?loadedTimeStamp=loadedTimeStamp, ?otherFlags=otherFlags, ?useFsiAuxLib=useFsiAuxLib)
member ic.GetProjectOptionsFromScript(filename, source, ?loadedTimeStamp, ?otherFlags, ?useFsiAuxLib, ?extraProjectInfo: obj) =
backgroundCompiler.GetProjectOptionsFromScript(filename,source,?loadedTimeStamp=loadedTimeStamp, ?otherFlags=otherFlags, ?useFsiAuxLib=useFsiAuxLib, ?extraProjectInfo=extraProjectInfo)

member ic.GetProjectOptionsFromCommandLineArgs(projectFileName, argv, ?loadedTimeStamp) =
member ic.GetProjectOptionsFromCommandLineArgs(projectFileName, argv, ?loadedTimeStamp, ?extraProjectInfo: obj) =
let loadedTimeStamp = defaultArg loadedTimeStamp DateTime.MaxValue // Not 'now', we don't want to force reloading
{ ProjectFileName = projectFileName
ProjectFileNames = [| |] // the project file names will be inferred from the ProjectOptions
Expand All @@ -2676,7 +2678,8 @@ type FSharpChecker(referenceResolver, projectCacheSize, keepAssemblyContents, ke
IsIncompleteTypeCheckEnvironment = false
UseScriptResolutionRules = false
LoadTime = loadedTimeStamp
UnresolvedReferences = None }
UnresolvedReferences = None
ExtraProjectInfo=extraProjectInfo }

/// Begin background parsing the given project.
member ic.StartBackgroundCompile(options) = backgroundCompiler.CheckProjectInBackground(options)
Expand Down
14 changes: 8 additions & 6 deletions src/fsharp/vs/service.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,8 @@ type internal FSharpProjectOptions =
LoadTime : DateTime
/// Unused in this API and should be 'None'
UnresolvedReferences : UnresolvedReferencesSet option
/// Extra information passed back on event trigger
ExtraProjectInfo : obj option
}


Expand Down Expand Up @@ -473,7 +475,7 @@ type internal FSharpChecker =
/// <param name="loadedTimeStamp">Indicates when the script was loaded into the editing environment,
/// so that an 'unload' and 'reload' action will cause the script to be considered as a new project,
/// so that references are re-resolved.</param>
member GetProjectOptionsFromScript : filename: string * source: string * ?loadedTimeStamp: DateTime * ?otherFlags: string[] * ?useFsiAuxLib: bool -> Async<FSharpProjectOptions>
member GetProjectOptionsFromScript : filename: string * source: string * ?loadedTimeStamp: DateTime * ?otherFlags: string[] * ?useFsiAuxLib: bool * ?extraProjectInfo: obj -> Async<FSharpProjectOptions>

/// <summary>
/// <para>Get the FSharpProjectOptions implied by a set of command line arguments.</para>
Expand All @@ -484,7 +486,7 @@ type internal FSharpChecker =
/// <param name="loadedTimeStamp">Indicates when the script was loaded into the editing environment,
/// so that an 'unload' and 'reload' action will cause the script to be considered as a new project,
/// so that references are re-resolved.</param>
member GetProjectOptionsFromCommandLineArgs : projectFileName: string * argv: string[] * ?loadedTimeStamp: DateTime -> FSharpProjectOptions
member GetProjectOptionsFromCommandLineArgs : projectFileName: string * argv: string[] * ?loadedTimeStamp: DateTime * ?extraProjectInfo: obj -> FSharpProjectOptions
/// <summary>
/// <para>Like ParseFileInProject, but uses results from the background builder.</para>
Expand Down Expand Up @@ -558,17 +560,17 @@ type internal FSharpChecker =
/// and that the file has become eligible to be re-typechecked for errors.
///
/// The event will be raised on a background thread.
member BeforeBackgroundFileCheck : IEvent<string>
member BeforeBackgroundFileCheck : IEvent<string * obj option>

/// Raised after a parse of a file in the background analysis.
///
/// The event will be raised on a background thread.
member FileParsed : IEvent<string>
member FileParsed : IEvent<string * obj option>

/// Raised after a check of a file in the background analysis.
///
/// The event will be raised on a background thread.
member FileChecked : IEvent<string>
member FileChecked : IEvent<string * obj option>
/// Get or set a flag which controls if background work is started implicitly.
///
Expand All @@ -583,7 +585,7 @@ type internal FSharpChecker =
/// Notify the host that a project has been fully checked in the background (using file contents provided by the file system API)
///
/// The event may be raised on a background thread.
member ProjectChecked : IEvent<string>
member ProjectChecked : IEvent<string * obj option>

// For internal use only
member internal ReactorOps : IReactorOperations
Expand Down
3 changes: 2 additions & 1 deletion vsintegration/src/FSharp.Editor/BraceMatchingService.fs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ type internal FSharpBraceMatchingService() =
interface IBraceMatcher with
member this.FindBracesAsync(document, position, cancellationToken) =
async {
match FSharpLanguageService.GetOptions(document.Project.Id) with
let! optionsOpt = FSharpLanguageService.GetOptionsForDocumentOrProject(document)
match optionsOpt with
| Some(options) ->
let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
let! result = FSharpBraceMatchingService.GetBraceMatchingResult(sourceText, document.Name, options, position)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ type internal FSharpBreakpointResolutionService() =
interface IBreakpointResolutionService with
member this.ResolveBreakpointAsync(document: Document, textSpan: TextSpan, cancellationToken: CancellationToken): Task<BreakpointResolutionResult> =
async {
match FSharpLanguageService.GetOptions(document.Project.Id) with
let! optionsOpt = FSharpLanguageService.GetOptionsForDocumentOrProject(document)
match optionsOpt with
| Some(options) ->
let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
let! location = FSharpBreakpointResolutionService.GetBreakpointLocation(sourceText, document.Name, textSpan, options)
Expand Down
8 changes: 5 additions & 3 deletions vsintegration/src/FSharp.Editor/ColorizationService.fs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ type internal FSharpColorizationService() =

member this.AddSyntacticClassificationsAsync(document: Document, textSpan: TextSpan, result: List<ClassifiedSpan>, cancellationToken: CancellationToken) =
async {
let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
match FSharpLanguageService.GetOptions(document.Project.Id) with
let! optionsOpt = FSharpLanguageService.GetOptionsForDocumentOrProject(document)
match optionsOpt with
| Some(options) ->
let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, options.OtherOptions |> Seq.toList)
result.AddRange(CommonHelpers.getColorizationData(
document.Id, sourceText, textSpan, Some(document.FilePath), defines, cancellationToken))
Expand All @@ -47,7 +48,8 @@ type internal FSharpColorizationService() =

member this.AddSemanticClassificationsAsync(document: Document, textSpan: TextSpan, result: List<ClassifiedSpan>, cancellationToken: CancellationToken) =
async {
match FSharpLanguageService.GetOptions(document.Project.Id) with
let! optionsOpt = FSharpLanguageService.GetOptionsForDocumentOrProject(document)
match optionsOpt with
| Some(options) ->
let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
let! textVersion = document.GetTextVersionAsync(cancellationToken) |> Async.AwaitTask
Expand Down
4 changes: 3 additions & 1 deletion vsintegration/src/FSharp.Editor/CommonHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,9 @@ module CommonHelpers =
| None -> ()

result
with ex ->
with
| :? System.OperationCanceledException -> reraise()
| ex ->
Assert.Exception(ex)
List<ClassifiedSpan>()

Expand Down
9 changes: 6 additions & 3 deletions vsintegration/src/FSharp.Editor/CompletionProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,20 @@ type internal FSharpCompletionProvider(workspace: Workspace, serviceProvider: SV
let documentId = workspace.GetDocumentIdInCurrentContext(sourceText.Container)
let document = workspace.CurrentSolution.GetDocument(documentId)

// We use RunSynchronously here, which gets the
let optionsOpt = FSharpLanguageService.GetOptionsForDocumentOrProject(document) |> Async.RunSynchronously
let defines =
match FSharpLanguageService.GetOptions(document.Project.Id) with
match optionsOpt with
| None -> []
| Some(options) -> CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, options.OtherOptions |> Seq.toList)
document.Id, document.FilePath, defines
(document.Id, document.FilePath, defines)

FSharpCompletionProvider.ShouldTriggerCompletionAux(sourceText, caretPosition, trigger.Kind, getInfo)

override this.ProvideCompletionsAsync(context: Microsoft.CodeAnalysis.Completion.CompletionContext) =
async {
match FSharpLanguageService.GetOptions(context.Document.Project.Id) with
let! optionsOpt = FSharpLanguageService.GetOptionsForDocumentOrProject(context.Document)
match optionsOpt with
| Some(options) ->
let! sourceText = context.Document.GetTextAsync(context.CancellationToken) |> Async.AwaitTask
let! textVersion = context.Document.GetTextVersionAsync(context.CancellationToken) |> Async.AwaitTask
Expand Down
21 changes: 19 additions & 2 deletions vsintegration/src/FSharp.Editor/DocumentDiagnosticAnalyzer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ type internal FSharpDocumentDiagnosticAnalyzer() =
inherit DocumentDiagnosticAnalyzer()

static member GetDiagnostics(filePath: string, sourceText: SourceText, textVersionHash: int, options: FSharpProjectOptions, addSemanticErrors: bool) = async {


let! parseResults = FSharpLanguageService.Checker.ParseFileInProject(filePath, sourceText.ToString(), options)
let! errors = async {
if addSemanticErrors then
Expand Down Expand Up @@ -57,7 +59,8 @@ type internal FSharpDocumentDiagnosticAnalyzer() =

override this.AnalyzeSyntaxAsync(document: Document, cancellationToken: CancellationToken): Task<ImmutableArray<Diagnostic>> =
async {
match FSharpLanguageService.GetOptions(document.Project.Id) with
let! optionsOpt = FSharpLanguageService.GetOptionsForDocumentOrProject(document)
match optionsOpt with
| Some(options) ->
let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
let! textVersion = document.GetTextVersionAsync(cancellationToken) |> Async.AwaitTask
Expand All @@ -68,11 +71,25 @@ type internal FSharpDocumentDiagnosticAnalyzer() =

override this.AnalyzeSemanticsAsync(document: Document, cancellationToken: CancellationToken): Task<ImmutableArray<Diagnostic>> =
async {
match FSharpLanguageService.GetOptions(document.Project.Id) with
let! optionsOpt = FSharpLanguageService.GetOptionsForDocumentOrProject(document)
match optionsOpt with
| Some(options) ->
let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
let! textVersion = document.GetTextVersionAsync(cancellationToken) |> Async.AwaitTask
return! FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(document.FilePath, sourceText, textVersion.GetHashCode(), options, true)
| None -> return ImmutableArray<Diagnostic>.Empty
} |> CommonRoslynHelpers.StartAsyncAsTask cancellationToken


(*
[<DiagnosticAnalyzer(FSharpCommonConstants.FSharpLanguageName)>]
type internal FSharpDiagnosticAnalyzer() =
inherit DiagnosticAnalyzer()
override this.SupportedDiagnostics = CommonRoslynHelpers.SupportedDiagnostics()
override this.Initialize(context) =
context.RegisterCompilationStartAction(fun ctxt -> ())
context.RegisterCompilationAction(fun ctxt -> ())
context.RegisterOperationAction(fun ctxt -> ())
*)
Loading

0 comments on commit 5694c6b

Please sign in to comment.