Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfd3752d

Browse files
majochaKevinRansom
authored andcommitted
Setup F# projects sooner after solution load (dotnet#2469)
* setup projects as soon as possible* checker no longer used here* mailbox added* StartImmediate* no async* threadsafe ProjectInfoManager* fix bug introduced indotnet#2408* setup projects after solution load
1 parent490b9e1 commitfd3752d

File tree

1 file changed

+57
-70
lines changed

1 file changed

+57
-70
lines changed

‎vsintegration/src/FSharp.Editor/Common/LanguageService.fs‎

Lines changed: 57 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,9 @@ type internal ProjectInfoManager
125125

126126
/// Get the options for a project
127127
memberthis.TryGetOptionsForProject(projectId:ProjectId)=
128-
if projectTable.ContainsKey(projectId)then
129-
Some(projectTable.[projectId])
130-
else
131-
None
128+
match projectTable.TryGetValue(projectId)with
129+
|true, options-> Some options
130+
|_-> None
132131

133132
/// Get the exact options for a document or project
134133
memberthis.TryGetOptionsForDocumentOrProject(document:Document)=async{
@@ -137,9 +136,9 @@ type internal ProjectInfoManager
137136
// The options for a single-file script project are re-requested each time the file is analyzed. This is because the
138137
// single-file project may contain #load and #r references which are changing as the user edits, and we may need to re-analyze
139138
// to determine the latest settings. FCS keeps a cache to help ensure these are up-to-date.
140-
if singleFileProjectTable.ContainsKey(projectId)then
139+
match singleFileProjectTable.TryGetValue(projectId)with
140+
|true,(loadTime,_)->
141141
try
142-
letloadTime,_= singleFileProjectTable.[projectId]
143142
letfileName= document.FilePath
144143
let!cancellationToken= Async.CancellationToken
145144
let!sourceText= document.GetTextAsync(cancellationToken)
@@ -149,18 +148,16 @@ type internal ProjectInfoManager
149148
with ex->
150149
Assert.Exception(ex)
151150
return None
152-
elsereturn this.TryGetOptionsForProject(projectId)
151+
|_->return this.TryGetOptionsForProject(projectId)
153152
}
154153

155154
/// Get the options for a document or project relevant for syntax processing.
156155
/// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project options for a script.
157156
memberthis.TryGetOptionsForEditingDocumentOrProject(document:Document)=
158157
letprojectId= document.Project.Id
159-
if singleFileProjectTable.ContainsKey(projectId)then
160-
let_loadTime,originalOptions= singleFileProjectTable.[projectId]
161-
Some originalOptions
162-
else
163-
this.TryGetOptionsForProject(projectId)
158+
match singleFileProjectTable.TryGetValue(projectId)with
159+
|true,(_loadTime, originalOptions)-> Some originalOptions
160+
|_-> this.TryGetOptionsForProject(projectId)
164161

165162
// Used to expose FSharpChecker/ProjectInfo manager to diagnostic providers
166163
// Diagnostic providers can be executed in environment that does not use MEF so they can rely only
@@ -245,32 +242,59 @@ and
245242
internal FSharpLanguageService(package:FSharpPackage)=
246243
inherit AbstractLanguageService<FSharpPackage, FSharpLanguageService>(package)
247244

248-
letcheckerProvider= package.ComponentModel.DefaultExportProvider.GetExport<FSharpCheckerProvider>().Value
249245
letprojectInfoManager= package.ComponentModel.DefaultExportProvider.GetExport<ProjectInfoManager>().Value
250246

251247
letprojectDisplayNameOf projectFileName=
252248
if String.IsNullOrWhiteSpace projectFileNamethen projectFileName
253249
else Path.GetFileNameWithoutExtension projectFileName
254250

255-
letopenedProjects= Queue<IProvideProjectSite>()
251+
letsingleFileProjects= ConcurrentDictionary<_, AbstractProject>()
252+
253+
lettryRemoveSingleFileProject projectId=
254+
match singleFileProjects.TryRemove(projectId)with
255+
|true, project->
256+
projectInfoManager.RemoveSingleFileProject(projectId)
257+
project.Disconnect()
258+
|_->()
259+
260+
overridethis.Initialize()=
261+
base.Initialize()
256262

257-
do
258-
Events.SolutionEvents.OnAfterOpenProject.Add(fun(args: Events.OpenProjectEventArgs)->
259-
match args.Hierarchywith
260-
|:? IProvideProjectSiteas siteProvider->
261-
openedProjects.Enqueue(siteProvider)
262-
|_->())
263+
this.Workspace.Options<- this.Workspace.Options.WithChangedOption(Completion.CompletionOptions.BlockForCompletionItems, FSharpCommonConstants.FSharpLanguageName,false)
264+
this.Workspace.Options<- this.Workspace.Options.WithChangedOption(Shared.Options.ServiceFeatureOnOffOptions.ClosedFileDiagnostic, FSharpCommonConstants.FSharpLanguageName, Nullablefalse)
265+
266+
this.Workspace.DocumentClosed.Add<|fun args->
267+
tryRemoveSingleFileProject args.Document.Project.Id
268+
269+
Events.SolutionEvents.OnAfterCloseSolution.Add<|fun _->
270+
singleFileProjects.Keys|> Seq.iter tryRemoveSingleFileProject
271+
272+
letctx= System.Threading.SynchronizationContext.Current
263273

264-
memberthis.BatchSetupProjects()=
265-
if openedProjects.Count>0then
266-
letworkspace= package.ComponentModel.GetService<VisualStudioWorkspaceImpl>()
267-
for siteProviderin openedProjectsdo
268-
this.SetupProjectFile(siteProvider, workspace)
269-
openedProjects.Clear()
274+
let recsetupProjectsAfterSolutionOpen()=
275+
async{
276+
use openedProjects= MailboxProcessor.Start<|fun inbox->
277+
async{
278+
// waits for AfterOpenSolution and then starts projects setup
279+
do! Async.AwaitEvent Events.SolutionEvents.OnAfterOpenSolution|> Async.Ignore
280+
whiletruedo
281+
let!siteProvider= inbox.Receive()
282+
do! Async.SwitchToContext ctx
283+
this.SetupProjectFile(siteProvider, this.Workspace)}
284+
285+
use _= Events.SolutionEvents.OnAfterOpenProject|> Observable.subscribe(fun args->
286+
match args.Hierarchywith
287+
|:? IProvideProjectSiteas siteProvider-> openedProjects.Post(siteProvider)
288+
|_->())
289+
290+
do! Async.AwaitEvent Events.SolutionEvents.OnAfterCloseSolution|> Async.Ignore
291+
do! setupProjectsAfterSolutionOpen()
292+
}
293+
setupProjectsAfterSolutionOpen()|> Async.StartImmediate
270294

271295
/// Sync the information for the project
272296
memberthis.SyncProject(project:AbstractProject,projectContext:IWorkspaceProjectContext,site:IProjectSite,forceUpdate)=
273-
297+
async{
274298
lethashSetIgnoreCase x=new HashSet<string>(x, StringComparer.OrdinalIgnoreCase)
275299
letupdatedFiles= site.SourceFilesOnDisk()|> hashSetIgnoreCase
276300
letworkspaceFiles= project.GetCurrentDocuments()|> Seq.map(fun file-> file.FilePath)|> hashSetIgnoreCase
@@ -290,6 +314,7 @@ and
290314
// update the cached options
291315
if updatedthen
292316
projectInfoManager.UpdateProjectInfo(project.Id, site, project.Workspace)
317+
}|> Async.Start
293318

294319
memberthis.SetupProjectFile(siteProvider:IProvideProjectSite,workspace:VisualStudioWorkspaceImpl)=
295320
let recsetup(site:IProjectSite)=
@@ -341,15 +366,7 @@ and
341366
projectContext.AddSourceFile(fileName)
342367

343368
letproject= projectContext:?> AbstractProject
344-
letdocumentId= project.GetCurrentDocumentFromPath(fileName).Id
345-
346-
let reconDocumentClosed= EventHandler<DocumentEventArgs>(fun _ args->
347-
if args.Document.Id= documentIdthen
348-
projectInfoManager.RemoveSingleFileProject(projectId)
349-
project.Disconnect()
350-
workspace.DocumentClosed.RemoveHandler(onDocumentClosed)
351-
)
352-
workspace.DocumentClosed.AddHandler(onDocumentClosed)
369+
singleFileProjects.[projectId]<- project
353370

354371
overridethis.ContentTypeName= FSharpCommonConstants.FSharpContentTypeName
355372
overridethis.LanguageName= FSharpCommonConstants.FSharpLanguageName
@@ -362,11 +379,8 @@ and
362379

363380
overridethis.SetupNewTextView(textView)=
364381
base.SetupNewTextView(textView)
365-
letworkspace= package.ComponentModel.GetService<VisualStudioWorkspaceImpl>()
382+
366383
lettextViewAdapter= package.ComponentModel.GetService<IVsEditorAdaptersFactoryService>()
367-
368-
workspace.Options<- workspace.Options.WithChangedOption(Completion.CompletionOptions.BlockForCompletionItems, FSharpCommonConstants.FSharpLanguageName,false)
369-
workspace.Options<- workspace.Options.WithChangedOption(Shared.Options.ServiceFeatureOnOffOptions.ClosedFileDiagnostic, FSharpCommonConstants.FSharpLanguageName, Nullablefalse)
370384

371385
match textView.GetBuffer()with
372386
|(VSConstants.S_OK, textLines)->
@@ -375,38 +389,11 @@ and
375389
| Some(hier,_)->
376390
match hierwith
377391
|:? IProvideProjectSiteas siteProviderwhennot(IsScript(filename))->
378-
this.SetupProjectFile(siteProvider,workspace)
392+
this.SetupProjectFile(siteProvider,this.Workspace)
379393
|_->
380394
letfileContents= VsTextLines.GetFileContents(textLines, textViewAdapter)
381-
this.SetupStandAloneFile(filename, fileContents,workspace, hier)
395+
this.SetupStandAloneFile(filename, fileContents,this.Workspace, hier)
382396
|_->()
383397
|_->()
384398

385-
// This is the second half of the bridge between the F# IncrementalBuild analysis engine and the Roslyn analysis
386-
// engine. When a document gets the focus, we call FSharpLanguageService.Checker.StartBackgroundCompile for the
387-
// project containing that file. This ensures the F# IncrementalBuild engine starts analyzing the project.
388-
letwpfTextView= textViewAdapter.GetWpfTextView(textView)
389-
match wpfTextView.TextBuffer.Properties.TryGetProperty<ITextDocument>(typeof<ITextDocument>)with
390-
|true, textDocument->
391-
letfilePath= textDocument.FilePath
392-
letonGotFocus=new EventHandler(fun _ _->
393-
for documentIdin workspace.CurrentSolution.GetDocumentIdsWithFilePath(filePath)do
394-
letdocument= workspace.CurrentSolution.GetDocument(documentId)
395-
match projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document)with
396-
| Some options-> checkerProvider.Checker.StartBackgroundCompile(options)
397-
| None->()
398-
)
399-
let reconViewClosed=new EventHandler(fun _ _->
400-
wpfTextView.GotAggregateFocus.RemoveHandler(onGotFocus)
401-
wpfTextView.Closed.RemoveHandler(onViewClosed)
402-
)
403-
wpfTextView.GotAggregateFocus.AddHandler(onGotFocus)
404-
wpfTextView.Closed.AddHandler(onViewClosed)
405-
|_->()
406-
407-
// When the text view is opened, setup all remaining projects on the background.
408-
async{
409-
do this.BatchSetupProjects()
410-
}
411-
|> Async.StartImmediate
412-
399+

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp